diff --git a/[refs] b/[refs]
index 931c6f400b82..eed734557a68 100644
--- a/[refs]
+++ b/[refs]
@@ -1,2 +1,2 @@
---
-refs/heads/master: bd3b49f25a3eae2d91432247b7565489120b6bcf
+refs/heads/master: e3fef09dda9ebf113a9a861260eff6f223808043
diff --git a/trunk/Documentation/DocBook/drm.tmpl b/trunk/Documentation/DocBook/drm.tmpl
index 4ee2304f82f9..c9cbb3fe0e6a 100644
--- a/trunk/Documentation/DocBook/drm.tmpl
+++ b/trunk/Documentation/DocBook/drm.tmpl
@@ -1611,10 +1611,10 @@ void intel_crt_init(struct drm_device *dev)
-
+
- Mode Setting Helper Functions
+ Mid-layer Helper Functions
The CRTC, encoder and connector functions provided by the drivers
implement the DRM API. They're called by the DRM core and ioctl handlers
@@ -2096,21 +2096,6 @@ void intel_crt_init(struct drm_device *dev)
-
- Modeset Helper Functions Reference
-!Edrivers/gpu/drm/drm_crtc_helper.c
-
-
- fbdev Helper Functions Reference
-!Pdrivers/gpu/drm/drm_fb_helper.c fbdev helpers
-!Edrivers/gpu/drm/drm_fb_helper.c
-
-
- Display Port Helper Functions Reference
-!Pdrivers/gpu/drm/drm_dp_helper.c dp helpers
-!Iinclude/drm/drm_dp_helper.h
-!Edrivers/gpu/drm/drm_dp_helper.c
-
diff --git a/trunk/Documentation/kref.txt b/trunk/Documentation/kref.txt
index ddf85a5dde0c..48ba715d5a63 100644
--- a/trunk/Documentation/kref.txt
+++ b/trunk/Documentation/kref.txt
@@ -213,91 +213,3 @@ presentation on krefs, which can be found at:
and:
http://www.kroah.com/linux/talks/ols_2004_kref_talk/
-
-The above example could also be optimized using kref_get_unless_zero() in
-the following way:
-
-static struct my_data *get_entry()
-{
- struct my_data *entry = NULL;
- mutex_lock(&mutex);
- if (!list_empty(&q)) {
- entry = container_of(q.next, struct my_data, link);
- if (!kref_get_unless_zero(&entry->refcount))
- entry = NULL;
- }
- mutex_unlock(&mutex);
- return entry;
-}
-
-static void release_entry(struct kref *ref)
-{
- struct my_data *entry = container_of(ref, struct my_data, refcount);
-
- mutex_lock(&mutex);
- list_del(&entry->link);
- mutex_unlock(&mutex);
- kfree(entry);
-}
-
-static void put_entry(struct my_data *entry)
-{
- kref_put(&entry->refcount, release_entry);
-}
-
-Which is useful to remove the mutex lock around kref_put() in put_entry(), but
-it's important that kref_get_unless_zero is enclosed in the same critical
-section that finds the entry in the lookup table,
-otherwise kref_get_unless_zero may reference already freed memory.
-Note that it is illegal to use kref_get_unless_zero without checking its
-return value. If you are sure (by already having a valid pointer) that
-kref_get_unless_zero() will return true, then use kref_get() instead.
-
-The function kref_get_unless_zero also makes it possible to use rcu
-locking for lookups in the above example:
-
-struct my_data
-{
- struct rcu_head rhead;
- .
- struct kref refcount;
- .
- .
-};
-
-static struct my_data *get_entry_rcu()
-{
- struct my_data *entry = NULL;
- rcu_read_lock();
- if (!list_empty(&q)) {
- entry = container_of(q.next, struct my_data, link);
- if (!kref_get_unless_zero(&entry->refcount))
- entry = NULL;
- }
- rcu_read_unlock();
- return entry;
-}
-
-static void release_entry_rcu(struct kref *ref)
-{
- struct my_data *entry = container_of(ref, struct my_data, refcount);
-
- mutex_lock(&mutex);
- list_del_rcu(&entry->link);
- mutex_unlock(&mutex);
- kfree_rcu(entry, rhead);
-}
-
-static void put_entry(struct my_data *entry)
-{
- kref_put(&entry->refcount, release_entry_rcu);
-}
-
-But note that the struct kref member needs to remain in valid memory for a
-rcu grace period after release_entry_rcu was called. That can be accomplished
-by using kfree_rcu(entry, rhead) as done above, or by calling synchronize_rcu()
-before using kfree, but note that synchronize_rcu() may sleep for a
-substantial amount of time.
-
-
-Thomas Hellstrom
diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS
index 2f66431bc698..59203e77ce9e 100644
--- a/trunk/MAINTAINERS
+++ b/trunk/MAINTAINERS
@@ -2512,15 +2512,6 @@ S: Supported
F: drivers/gpu/drm/exynos
F: include/drm/exynos*
-DRM DRIVERS FOR NVIDIA TEGRA
-M: Thierry Reding
-L: dri-devel@lists.freedesktop.org
-L: linux-tegra@vger.kernel.org
-T: git git://gitorious.org/thierryreding/linux.git
-S: Maintained
-F: drivers/gpu/drm/tegra/
-F: Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
-
DSCC4 DRIVER
M: Francois Romieu
L: netdev@vger.kernel.org
diff --git a/trunk/drivers/gpu/drm/Makefile b/trunk/drivers/gpu/drm/Makefile
index 6f58c81cfcbc..ac91a339b042 100644
--- a/trunk/drivers/gpu/drm/Makefile
+++ b/trunk/drivers/gpu/drm/Makefile
@@ -8,7 +8,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_context.o drm_dma.o \
drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
- drm_agpsupport.o drm_scatter.o drm_pci.o \
+ drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
drm_crtc.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \
@@ -16,7 +16,6 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
-drm-$(CONFIG_PCI) += ati_pcigart.o
drm-usb-y := drm_usb.o
diff --git a/trunk/drivers/gpu/drm/drm_crtc_helper.c b/trunk/drivers/gpu/drm/drm_crtc_helper.c
index 7b2d378b2576..1fe719fb32e8 100644
--- a/trunk/drivers/gpu/drm/drm_crtc_helper.c
+++ b/trunk/drivers/gpu/drm/drm_crtc_helper.c
@@ -39,17 +39,6 @@
#include
#include
-/**
- * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
- * connector list
- * @dev: drm device to operate on
- *
- * Some userspace presumes that the first connected connector is the main
- * display, where it's supposed to display e.g. the login screen. For
- * laptops, this should be the main panel. Use this function to sort all
- * (eDP/LVDS) panels to the front of the connector list, instead of
- * painstakingly trying to initialize them in the right order.
- */
void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
{
struct drm_connector *connector, *tmp;
@@ -93,21 +82,22 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
/**
* drm_helper_probe_single_connector_modes - get complete set of display modes
- * @connector: connector to probe
+ * @dev: DRM device
* @maxX: max width for modes
* @maxY: max height for modes
*
* LOCKING:
* Caller must hold mode config lock.
*
- * Based on the helper callbacks implemented by @connector try to detect all
- * valid modes. Modes will first be added to the connector's probed_modes list,
- * then culled (based on validity and the @maxX, @maxY parameters) and put into
- * the normal modes list.
+ * Based on @dev's mode_config layout, scan all the connectors and try to detect
+ * modes on them. Modes will first be added to the connector's probed_modes
+ * list, then culled (based on validity and the @maxX, @maxY parameters) and
+ * put into the normal modes list.
+ *
+ * Intended to be used either at bootup time or when major configuration
+ * changes have occurred.
*
- * Intended to be use as a generic implementation of the ->probe() @connector
- * callback for drivers that use the crtc helpers for output mode filtering and
- * detection.
+ * FIXME: take into account monitor limits
*
* RETURNS:
* Number of modes found on @connector.
@@ -358,24 +348,17 @@ drm_crtc_prepare_encoders(struct drm_device *dev)
}
/**
- * drm_crtc_helper_set_mode - internal helper to set a mode
+ * drm_crtc_set_mode - set a mode
* @crtc: CRTC to program
* @mode: mode to use
* @x: horizontal offset into the surface
* @y: vertical offset into the surface
- * @old_fb: old framebuffer, for cleanup
*
* LOCKING:
* Caller must hold mode config lock.
*
* Try to set @mode on @crtc. Give @crtc and its associated connectors a chance
- * to fixup or reject the mode prior to trying to set it. This is an internal
- * helper that drivers could e.g. use to update properties that require the
- * entire output pipe to be disabled and re-enabled in a new configuration. For
- * example for changing whether audio is enabled on a hdmi link or for changing
- * panel fitter or dither attributes. It is also called by the
- * drm_crtc_helper_set_config() helper function to drive the mode setting
- * sequence.
+ * to fixup or reject the mode prior to trying to set it.
*
* RETURNS:
* True if the mode was set successfully, or false otherwise.
@@ -531,19 +514,20 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
/**
* drm_crtc_helper_set_config - set a new config from userspace
- * @set: mode set configuration
+ * @crtc: CRTC to setup
+ * @crtc_info: user provided configuration
+ * @new_mode: new mode to set
+ * @connector_set: set of connectors for the new config
+ * @fb: new framebuffer
*
* LOCKING:
* Caller must hold mode config lock.
*
- * Setup a new configuration, provided by the upper layers (either an ioctl call
- * from userspace or internally e.g. from the fbdev suppport code) in @set, and
- * enable it. This is the main helper functions for drivers that implement
- * kernel mode setting with the crtc helper functions and the assorted
- * ->prepare(), ->modeset() and ->commit() helper callbacks.
+ * Setup a new configuration, provided by the user in @crtc_info, and enable
+ * it.
*
* RETURNS:
- * Returns 0 on success, -ERRNO on failure.
+ * Zero. (FIXME)
*/
int drm_crtc_helper_set_config(struct drm_mode_set *set)
{
@@ -839,14 +823,12 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
}
/**
- * drm_helper_connector_dpms() - connector dpms helper implementation
- * @connector: affected connector
- * @mode: DPMS mode
+ * drm_helper_connector_dpms
+ * @connector affected connector
+ * @mode DPMS mode
*
- * This is the main helper function provided by the crtc helper framework for
- * implementing the DPMS connector attribute. It computes the new desired DPMS
- * state for all encoders and crtcs in the output mesh and calls the ->dpms()
- * callback provided by the driver appropriately.
+ * Calls the low-level connector DPMS function, then
+ * calls appropriate encoder and crtc DPMS functions as well
*/
void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
{
diff --git a/trunk/drivers/gpu/drm/drm_dp_helper.c b/trunk/drivers/gpu/drm/drm_dp_helper.c
index 89e196627160..3c4cccd0d753 100644
--- a/trunk/drivers/gpu/drm/drm_dp_helper.c
+++ b/trunk/drivers/gpu/drm/drm_dp_helper.c
@@ -30,15 +30,6 @@
#include
#include
-/**
- * DOC: dp helpers
- *
- * These functions contain some common logic and helpers at various abstraction
- * levels to deal with Display Port sink devices and related things like DP aux
- * channel transfers, EDID reading over DP aux channels, decoding certain DPCD
- * blocks, ...
- */
-
/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
static int
i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
@@ -202,18 +193,6 @@ i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
return 0;
}
-/**
- * i2c_dp_aux_add_bus() - register an i2c adapter using the aux ch helper
- * @adapter: i2c adapter to register
- *
- * This registers an i2c adapater that uses dp aux channel as it's underlaying
- * transport. The driver needs to fill out the &i2c_algo_dp_aux_data structure
- * and store it in the algo_data member of the @adapter argument. This will be
- * used by the i2c over dp aux algorithm to drive the hardware.
- *
- * RETURNS:
- * 0 on success, -ERRNO on failure.
- */
int
i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
{
diff --git a/trunk/drivers/gpu/drm/drm_edid.c b/trunk/drivers/gpu/drm/drm_edid.c
index 484c36a4b7a5..164820003546 100644
--- a/trunk/drivers/gpu/drm/drm_edid.c
+++ b/trunk/drivers/gpu/drm/drm_edid.c
@@ -1639,7 +1639,7 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
if (len >= 12)
connector->audio_latency[1] = db[12];
- DRM_DEBUG_KMS("HDMI: DVI dual %d, "
+ DRM_LOG_KMS("HDMI: DVI dual %d, "
"max TMDS clock %d, "
"latency present %d %d, "
"video latency %d %d, "
diff --git a/trunk/drivers/gpu/drm/drm_fb_helper.c b/trunk/drivers/gpu/drm/drm_fb_helper.c
index 05e623a5d095..2c44af691e98 100644
--- a/trunk/drivers/gpu/drm/drm_fb_helper.c
+++ b/trunk/drivers/gpu/drm/drm_fb_helper.c
@@ -45,15 +45,6 @@ MODULE_LICENSE("GPL and additional rights");
static LIST_HEAD(kernel_fb_helper_list);
-/**
- * DOC: fbdev helpers
- *
- * The fb helper functions are useful to provide an fbdev on top of a drm kernel
- * mode setting driver. They can be used mostly independantely from the crtc
- * helper functions used by many drivers to implement the kernel mode setting
- * interfaces.
- */
-
/* simple single crtc case helper function */
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
{
@@ -1311,14 +1302,12 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
/**
* drm_helper_initial_config - setup a sane initial connector configuration
- * @fb_helper: fb_helper device struct
- * @bpp_sel: bpp value to use for the framebuffer configuration
+ * @dev: DRM device
*
* LOCKING:
- * Called at init time by the driver to set up the @fb_helper initial
- * configuration, must take the mode config lock.
+ * Called at init time, must take mode config lock.
*
- * Scans the CRTCs and connectors and tries to put together an initial setup.
+ * Scan the CRTCs and connectors and try to put together an initial setup.
* At the moment, this is a cloned configuration across all heads with
* a new framebuffer object as the backing store.
*
@@ -1352,7 +1341,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
/**
* drm_fb_helper_hotplug_event - respond to a hotplug notification by
- * probing all the outputs attached to the fb
+ * probing all the outputs attached to the fb.
* @fb_helper: the drm_fb_helper
*
* LOCKING:
diff --git a/trunk/drivers/gpu/drm/drm_hashtab.c b/trunk/drivers/gpu/drm/drm_hashtab.c
index 80254547a3f8..5729e390aa4e 100644
--- a/trunk/drivers/gpu/drm/drm_hashtab.c
+++ b/trunk/drivers/gpu/drm/drm_hashtab.c
@@ -67,7 +67,7 @@ void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
hashed_key = hash_long(key, ht->order);
DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
h_list = &ht->table[hashed_key];
- hlist_for_each_entry(entry, list, h_list, head)
+ hlist_for_each_entry_rcu(entry, list, h_list, head)
DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
}
@@ -79,25 +79,6 @@ static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht,
struct hlist_node *list;
unsigned int hashed_key;
- hashed_key = hash_long(key, ht->order);
- h_list = &ht->table[hashed_key];
- hlist_for_each_entry(entry, list, h_list, head) {
- if (entry->key == key)
- return list;
- if (entry->key > key)
- break;
- }
- return NULL;
-}
-
-static struct hlist_node *drm_ht_find_key_rcu(struct drm_open_hash *ht,
- unsigned long key)
-{
- struct drm_hash_item *entry;
- struct hlist_head *h_list;
- struct hlist_node *list;
- unsigned int hashed_key;
-
hashed_key = hash_long(key, ht->order);
h_list = &ht->table[hashed_key];
hlist_for_each_entry_rcu(entry, list, h_list, head) {
@@ -109,6 +90,7 @@ static struct hlist_node *drm_ht_find_key_rcu(struct drm_open_hash *ht,
return NULL;
}
+
int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
{
struct drm_hash_item *entry;
@@ -120,7 +102,7 @@ int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
hashed_key = hash_long(key, ht->order);
h_list = &ht->table[hashed_key];
parent = NULL;
- hlist_for_each_entry(entry, list, h_list, head) {
+ hlist_for_each_entry_rcu(entry, list, h_list, head) {
if (entry->key == key)
return -EINVAL;
if (entry->key > key)
@@ -170,7 +152,7 @@ int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
{
struct hlist_node *list;
- list = drm_ht_find_key_rcu(ht, key);
+ list = drm_ht_find_key(ht, key);
if (!list)
return -EINVAL;
diff --git a/trunk/drivers/gpu/drm/drm_pci.c b/trunk/drivers/gpu/drm/drm_pci.c
index 754bc96e10c7..ba33144257e5 100644
--- a/trunk/drivers/gpu/drm/drm_pci.c
+++ b/trunk/drivers/gpu/drm/drm_pci.c
@@ -470,7 +470,7 @@ int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask)
{
struct pci_dev *root;
int pos;
- u32 lnkcap = 0, lnkcap2 = 0;
+ u32 lnkcap, lnkcap2;
*mask = 0;
if (!dev->pdev)
diff --git a/trunk/drivers/gpu/drm/i915/intel_pm.c b/trunk/drivers/gpu/drm/i915/intel_pm.c
index 0cbc0e6402b4..0edb549d1434 100644
--- a/trunk/drivers/gpu/drm/i915/intel_pm.c
+++ b/trunk/drivers/gpu/drm/i915/intel_pm.c
@@ -2552,7 +2552,8 @@ static void gen6_update_ring_freq(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int min_freq = 15;
- int gpu_freq, ia_freq, max_ia_freq;
+ int gpu_freq;
+ unsigned int ia_freq, max_ia_freq;
int scaling_factor = 180;
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
diff --git a/trunk/drivers/gpu/drm/nouveau/Makefile b/trunk/drivers/gpu/drm/nouveau/Makefile
index ab25752a0b1e..a990df4d6c04 100644
--- a/trunk/drivers/gpu/drm/nouveau/Makefile
+++ b/trunk/drivers/gpu/drm/nouveau/Makefile
@@ -11,7 +11,6 @@ nouveau-y := core/core/client.o
nouveau-y += core/core/engctx.o
nouveau-y += core/core/engine.o
nouveau-y += core/core/enum.o
-nouveau-y += core/core/falcon.o
nouveau-y += core/core/gpuobj.o
nouveau-y += core/core/handle.o
nouveau-y += core/core/mm.o
@@ -30,7 +29,6 @@ nouveau-y += core/subdev/bios/base.o
nouveau-y += core/subdev/bios/bit.o
nouveau-y += core/subdev/bios/conn.o
nouveau-y += core/subdev/bios/dcb.o
-nouveau-y += core/subdev/bios/disp.o
nouveau-y += core/subdev/bios/dp.o
nouveau-y += core/subdev/bios/extdev.o
nouveau-y += core/subdev/bios/gpio.o
@@ -66,19 +64,9 @@ nouveau-y += core/subdev/devinit/nv50.o
nouveau-y += core/subdev/fb/base.o
nouveau-y += core/subdev/fb/nv04.o
nouveau-y += core/subdev/fb/nv10.o
-nouveau-y += core/subdev/fb/nv1a.o
nouveau-y += core/subdev/fb/nv20.o
-nouveau-y += core/subdev/fb/nv25.o
nouveau-y += core/subdev/fb/nv30.o
-nouveau-y += core/subdev/fb/nv35.o
-nouveau-y += core/subdev/fb/nv36.o
nouveau-y += core/subdev/fb/nv40.o
-nouveau-y += core/subdev/fb/nv41.o
-nouveau-y += core/subdev/fb/nv44.o
-nouveau-y += core/subdev/fb/nv46.o
-nouveau-y += core/subdev/fb/nv47.o
-nouveau-y += core/subdev/fb/nv49.o
-nouveau-y += core/subdev/fb/nv4e.o
nouveau-y += core/subdev/fb/nv50.o
nouveau-y += core/subdev/fb/nvc0.o
nouveau-y += core/subdev/gpio/base.o
@@ -123,10 +111,7 @@ nouveau-y += core/engine/dmaobj/base.o
nouveau-y += core/engine/dmaobj/nv04.o
nouveau-y += core/engine/dmaobj/nv50.o
nouveau-y += core/engine/dmaobj/nvc0.o
-nouveau-y += core/engine/dmaobj/nvd0.o
nouveau-y += core/engine/bsp/nv84.o
-nouveau-y += core/engine/bsp/nvc0.o
-nouveau-y += core/engine/bsp/nve0.o
nouveau-y += core/engine/copy/nva3.o
nouveau-y += core/engine/copy/nvc0.o
nouveau-y += core/engine/copy/nve0.o
@@ -134,21 +119,7 @@ nouveau-y += core/engine/crypt/nv84.o
nouveau-y += core/engine/crypt/nv98.o
nouveau-y += core/engine/disp/nv04.o
nouveau-y += core/engine/disp/nv50.o
-nouveau-y += core/engine/disp/nv84.o
-nouveau-y += core/engine/disp/nv94.o
-nouveau-y += core/engine/disp/nva0.o
-nouveau-y += core/engine/disp/nva3.o
nouveau-y += core/engine/disp/nvd0.o
-nouveau-y += core/engine/disp/nve0.o
-nouveau-y += core/engine/disp/dacnv50.o
-nouveau-y += core/engine/disp/hdanva3.o
-nouveau-y += core/engine/disp/hdanvd0.o
-nouveau-y += core/engine/disp/hdminv84.o
-nouveau-y += core/engine/disp/hdminva3.o
-nouveau-y += core/engine/disp/hdminvd0.o
-nouveau-y += core/engine/disp/sornv50.o
-nouveau-y += core/engine/disp/sornv94.o
-nouveau-y += core/engine/disp/sornvd0.o
nouveau-y += core/engine/disp/vga.o
nouveau-y += core/engine/fifo/base.o
nouveau-y += core/engine/fifo/nv04.o
@@ -180,14 +151,11 @@ nouveau-y += core/engine/mpeg/nv40.o
nouveau-y += core/engine/mpeg/nv50.o
nouveau-y += core/engine/mpeg/nv84.o
nouveau-y += core/engine/ppp/nv98.o
-nouveau-y += core/engine/ppp/nvc0.o
nouveau-y += core/engine/software/nv04.o
nouveau-y += core/engine/software/nv10.o
nouveau-y += core/engine/software/nv50.o
nouveau-y += core/engine/software/nvc0.o
nouveau-y += core/engine/vp/nv84.o
-nouveau-y += core/engine/vp/nvc0.o
-nouveau-y += core/engine/vp/nve0.o
# drm/core
nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
@@ -198,7 +166,7 @@ nouveau-y += nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o
# drm/kms
nouveau-y += nouveau_bios.o nouveau_fbcon.o nouveau_display.o
-nouveau-y += nouveau_connector.o nouveau_dp.o
+nouveau-y += nouveau_connector.o nouveau_hdmi.o nouveau_dp.o
nouveau-y += nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o
# drm/kms/nv04:nv50
@@ -207,7 +175,9 @@ nouveau-y += nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o
nouveau-y += nv04_crtc.o nv04_display.o nv04_cursor.o
# drm/kms/nv50-
-nouveau-y += nv50_display.o
+nouveau-y += nv50_display.o nvd0_display.o
+nouveau-y += nv50_crtc.o nv50_dac.o nv50_sor.o nv50_cursor.o
+nouveau-y += nv50_evo.o
# drm/pm
nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o
diff --git a/trunk/drivers/gpu/drm/nouveau/core/core/engctx.c b/trunk/drivers/gpu/drm/nouveau/core/core/engctx.c
index 84c71fad2b6c..e41b10d5eb59 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/core/engctx.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/core/engctx.c
@@ -189,21 +189,6 @@ nouveau_engctx_fini(struct nouveau_engctx *engctx, bool suspend)
return nouveau_gpuobj_fini(&engctx->base, suspend);
}
-int
-_nouveau_engctx_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_engctx *engctx;
- int ret;
-
- ret = nouveau_engctx_create(parent, engine, oclass, NULL, 256, 256,
- NVOBJ_FLAG_ZERO_ALLOC, &engctx);
- *pobject = nv_object(engctx);
- return ret;
-}
-
void
_nouveau_engctx_dtor(struct nouveau_object *object)
{
diff --git a/trunk/drivers/gpu/drm/nouveau/core/core/falcon.c b/trunk/drivers/gpu/drm/nouveau/core/core/falcon.c
deleted file mode 100644
index 6b0843c33877..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/core/falcon.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright 2012 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.
- */
-
-#include
-
-#include
-
-u32
-_nouveau_falcon_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_falcon *falcon = (void *)object;
- return nv_rd32(falcon, falcon->addr + addr);
-}
-
-void
-_nouveau_falcon_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nouveau_falcon *falcon = (void *)object;
- nv_wr32(falcon, falcon->addr + addr, data);
-}
-
-int
-_nouveau_falcon_init(struct nouveau_object *object)
-{
- struct nouveau_device *device = nv_device(object);
- struct nouveau_falcon *falcon = (void *)object;
- const struct firmware *fw;
- char name[32] = "internal";
- int ret, i;
- u32 caps;
-
- /* enable engine, and determine its capabilities */
- ret = nouveau_engine_init(&falcon->base);
- if (ret)
- return ret;
-
- if (device->chipset < 0xa3 ||
- device->chipset == 0xaa || device->chipset == 0xac) {
- falcon->version = 0;
- falcon->secret = (falcon->addr == 0x087000) ? 1 : 0;
- } else {
- caps = nv_ro32(falcon, 0x12c);
- falcon->version = (caps & 0x0000000f);
- falcon->secret = (caps & 0x00000030) >> 4;
- }
-
- caps = nv_ro32(falcon, 0x108);
- falcon->code.limit = (caps & 0x000001ff) << 8;
- falcon->data.limit = (caps & 0x0003fe00) >> 1;
-
- nv_debug(falcon, "falcon version: %d\n", falcon->version);
- nv_debug(falcon, "secret level: %d\n", falcon->secret);
- nv_debug(falcon, "code limit: %d\n", falcon->code.limit);
- nv_debug(falcon, "data limit: %d\n", falcon->data.limit);
-
- /* wait for 'uc halted' to be signalled before continuing */
- if (falcon->secret) {
- nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
- nv_wo32(falcon, 0x004, 0x00000010);
- }
-
- /* disable all interrupts */
- nv_wo32(falcon, 0x014, 0xffffffff);
-
- /* no default ucode provided by the engine implementation, try and
- * locate a "self-bootstrapping" firmware image for the engine
- */
- if (!falcon->code.data) {
- snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x",
- device->chipset, falcon->addr >> 12);
-
- ret = request_firmware(&fw, name, &device->pdev->dev);
- if (ret == 0) {
- falcon->code.data = kmemdup(fw->data, fw->size, GFP_KERNEL);
- falcon->code.size = fw->size;
- falcon->data.data = NULL;
- falcon->data.size = 0;
- release_firmware(fw);
- }
-
- falcon->external = true;
- }
-
- /* next step is to try and load "static code/data segment" firmware
- * images for the engine
- */
- if (!falcon->code.data) {
- snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd",
- device->chipset, falcon->addr >> 12);
-
- ret = request_firmware(&fw, name, &device->pdev->dev);
- if (ret) {
- nv_error(falcon, "unable to load firmware data\n");
- return ret;
- }
-
- falcon->data.data = kmemdup(fw->data, fw->size, GFP_KERNEL);
- falcon->data.size = fw->size;
- release_firmware(fw);
- if (!falcon->data.data)
- return -ENOMEM;
-
- snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc",
- device->chipset, falcon->addr >> 12);
-
- ret = request_firmware(&fw, name, &device->pdev->dev);
- if (ret) {
- nv_error(falcon, "unable to load firmware code\n");
- return ret;
- }
-
- falcon->code.data = kmemdup(fw->data, fw->size, GFP_KERNEL);
- falcon->code.size = fw->size;
- release_firmware(fw);
- if (!falcon->code.data)
- return -ENOMEM;
- }
-
- nv_debug(falcon, "firmware: %s (%s)\n", name, falcon->data.data ?
- "static code/data segments" : "self-bootstrapping");
-
- /* ensure any "self-bootstrapping" firmware image is in vram */
- if (!falcon->data.data && !falcon->core) {
- ret = nouveau_gpuobj_new(object->parent, NULL,
- falcon->code.size, 256, 0,
- &falcon->core);
- if (ret) {
- nv_error(falcon, "core allocation failed, %d\n", ret);
- return ret;
- }
-
- for (i = 0; i < falcon->code.size; i += 4)
- nv_wo32(falcon->core, i, falcon->code.data[i / 4]);
- }
-
- /* upload firmware bootloader (or the full code segments) */
- if (falcon->core) {
- if (device->card_type < NV_C0)
- nv_wo32(falcon, 0x618, 0x04000000);
- else
- nv_wo32(falcon, 0x618, 0x00000114);
- nv_wo32(falcon, 0x11c, 0);
- nv_wo32(falcon, 0x110, falcon->core->addr >> 8);
- nv_wo32(falcon, 0x114, 0);
- nv_wo32(falcon, 0x118, 0x00006610);
- } else {
- if (falcon->code.size > falcon->code.limit ||
- falcon->data.size > falcon->data.limit) {
- nv_error(falcon, "ucode exceeds falcon limit(s)\n");
- return -EINVAL;
- }
-
- if (falcon->version < 3) {
- nv_wo32(falcon, 0xff8, 0x00100000);
- for (i = 0; i < falcon->code.size / 4; i++)
- nv_wo32(falcon, 0xff4, falcon->code.data[i]);
- } else {
- nv_wo32(falcon, 0x180, 0x01000000);
- for (i = 0; i < falcon->code.size / 4; i++) {
- if ((i & 0x3f) == 0)
- nv_wo32(falcon, 0x188, i >> 6);
- nv_wo32(falcon, 0x184, falcon->code.data[i]);
- }
- }
- }
-
- /* upload data segment (if necessary), zeroing the remainder */
- if (falcon->version < 3) {
- nv_wo32(falcon, 0xff8, 0x00000000);
- for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
- nv_wo32(falcon, 0xff4, falcon->data.data[i]);
- for (; i < falcon->data.limit; i += 4)
- nv_wo32(falcon, 0xff4, 0x00000000);
- } else {
- nv_wo32(falcon, 0x1c0, 0x01000000);
- for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
- nv_wo32(falcon, 0x1c4, falcon->data.data[i]);
- for (; i < falcon->data.limit / 4; i++)
- nv_wo32(falcon, 0x1c4, 0x00000000);
- }
-
- /* start it running */
- nv_wo32(falcon, 0x10c, 0x00000001); /* BLOCK_ON_FIFO */
- nv_wo32(falcon, 0x104, 0x00000000); /* ENTRY */
- nv_wo32(falcon, 0x100, 0x00000002); /* TRIGGER */
- nv_wo32(falcon, 0x048, 0x00000003); /* FIFO | CHSW */
- return 0;
-}
-
-int
-_nouveau_falcon_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_falcon *falcon = (void *)object;
-
- if (!suspend) {
- nouveau_gpuobj_ref(NULL, &falcon->core);
- if (falcon->external) {
- kfree(falcon->data.data);
- kfree(falcon->code.data);
- falcon->code.data = NULL;
- }
- }
-
- nv_mo32(falcon, 0x048, 0x00000003, 0x00000000);
- nv_wo32(falcon, 0x014, 0xffffffff);
-
- return nouveau_engine_fini(&falcon->base, suspend);
-}
-
-int
-nouveau_falcon_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 addr, bool enable,
- const char *iname, const char *fname,
- int length, void **pobject)
-{
- struct nouveau_falcon *falcon;
- int ret;
-
- ret = nouveau_engine_create_(parent, engine, oclass, enable, iname,
- fname, length, pobject);
- falcon = *pobject;
- if (ret)
- return ret;
-
- falcon->addr = addr;
- return 0;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/core/gpuobj.c b/trunk/drivers/gpu/drm/nouveau/core/core/gpuobj.c
index 560b2214cf1c..70586fde69cf 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/core/gpuobj.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/core/gpuobj.c
@@ -183,7 +183,7 @@ _nouveau_gpuobj_fini(struct nouveau_object *object, bool suspend)
}
u32
-_nouveau_gpuobj_rd32(struct nouveau_object *object, u64 addr)
+_nouveau_gpuobj_rd32(struct nouveau_object *object, u32 addr)
{
struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
@@ -193,7 +193,7 @@ _nouveau_gpuobj_rd32(struct nouveau_object *object, u64 addr)
}
void
-_nouveau_gpuobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
+_nouveau_gpuobj_wr32(struct nouveau_object *object, u32 addr, u32 data)
{
struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/core/mm.c b/trunk/drivers/gpu/drm/nouveau/core/core/mm.c
index 0261a11b2ae0..a6d3cd6490f7 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/core/mm.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/core/mm.c
@@ -234,18 +234,15 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
int
nouveau_mm_fini(struct nouveau_mm *mm)
{
- if (nouveau_mm_initialised(mm)) {
- struct nouveau_mm_node *node, *heap =
- list_first_entry(&mm->nodes, typeof(*heap), nl_entry);
- int nodes = 0;
-
- list_for_each_entry(node, &mm->nodes, nl_entry) {
- if (WARN_ON(nodes++ == mm->heap_nodes))
- return -EBUSY;
- }
+ struct nouveau_mm_node *node, *heap =
+ list_first_entry(&mm->nodes, struct nouveau_mm_node, nl_entry);
+ int nodes = 0;
- kfree(heap);
+ list_for_each_entry(node, &mm->nodes, nl_entry) {
+ if (WARN_ON(nodes++ == mm->heap_nodes))
+ return -EBUSY;
}
+ kfree(heap);
return 0;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c b/trunk/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
index 1d9f614cb97d..66f7dfd907ee 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
@@ -22,13 +22,18 @@
* Authors: Ben Skeggs
*/
-#include
+#include
#include
+#include
#include
struct nv84_bsp_priv {
- struct nouveau_engine base;
+ struct nouveau_bsp base;
+};
+
+struct nv84_bsp_chan {
+ struct nouveau_bsp_chan base;
};
/*******************************************************************************
@@ -44,16 +49,61 @@ nv84_bsp_sclass[] = {
* BSP context
******************************************************************************/
+static int
+nv84_bsp_context_ctor(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nv84_bsp_chan *priv;
+ int ret;
+
+ ret = nouveau_bsp_context_create(parent, engine, oclass, NULL,
+ 0, 0, 0, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void
+nv84_bsp_context_dtor(struct nouveau_object *object)
+{
+ struct nv84_bsp_chan *priv = (void *)object;
+ nouveau_bsp_context_destroy(&priv->base);
+}
+
+static int
+nv84_bsp_context_init(struct nouveau_object *object)
+{
+ struct nv84_bsp_chan *priv = (void *)object;
+ int ret;
+
+ ret = nouveau_bsp_context_init(&priv->base);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+nv84_bsp_context_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nv84_bsp_chan *priv = (void *)object;
+ return nouveau_bsp_context_fini(&priv->base, suspend);
+}
+
static struct nouveau_oclass
nv84_bsp_cclass = {
.handle = NV_ENGCTX(BSP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_engctx_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
+ .ctor = nv84_bsp_context_ctor,
+ .dtor = nv84_bsp_context_dtor,
+ .init = nv84_bsp_context_init,
+ .fini = nv84_bsp_context_fini,
+ .rd32 = _nouveau_bsp_context_rd32,
+ .wr32 = _nouveau_bsp_context_wr32,
},
};
@@ -61,6 +111,11 @@ nv84_bsp_cclass = {
* BSP engine/subdev functions
******************************************************************************/
+static void
+nv84_bsp_intr(struct nouveau_subdev *subdev)
+{
+}
+
static int
nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@@ -69,25 +124,52 @@ nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv84_bsp_priv *priv;
int ret;
- ret = nouveau_engine_create(parent, engine, oclass, true,
- "PBSP", "bsp", &priv);
+ ret = nouveau_bsp_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x04008000;
+ nv_subdev(priv)->intr = nv84_bsp_intr;
nv_engine(priv)->cclass = &nv84_bsp_cclass;
nv_engine(priv)->sclass = nv84_bsp_sclass;
return 0;
}
+static void
+nv84_bsp_dtor(struct nouveau_object *object)
+{
+ struct nv84_bsp_priv *priv = (void *)object;
+ nouveau_bsp_destroy(&priv->base);
+}
+
+static int
+nv84_bsp_init(struct nouveau_object *object)
+{
+ struct nv84_bsp_priv *priv = (void *)object;
+ int ret;
+
+ ret = nouveau_bsp_init(&priv->base);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+nv84_bsp_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nv84_bsp_priv *priv = (void *)object;
+ return nouveau_bsp_fini(&priv->base, suspend);
+}
+
struct nouveau_oclass
nv84_bsp_oclass = {
.handle = NV_ENGINE(BSP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_bsp_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = _nouveau_engine_init,
- .fini = _nouveau_engine_fini,
+ .dtor = nv84_bsp_dtor,
+ .init = nv84_bsp_init,
+ .fini = nv84_bsp_fini,
},
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
deleted file mode 100644
index 0a5aa6bb0870..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Maarten Lankhorst
- *
- * 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: Maarten Lankhorst
- */
-
-#include
-
-#include
-
-struct nvc0_bsp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * BSP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_bsp_sclass[] = {
- { 0x90b1, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PBSP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_bsp_cclass = {
- .handle = NV_ENGCTX(BSP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PBSP engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_bsp_init(struct nouveau_object *object)
-{
- struct nvc0_bsp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x084010, 0x0000fff2);
- nv_wr32(priv, 0x08401c, 0x0000fff2);
- return 0;
-}
-
-static int
-nvc0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_bsp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
- "PBSP", "bsp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00008000;
- nv_engine(priv)->cclass = &nvc0_bsp_cclass;
- nv_engine(priv)->sclass = nvc0_bsp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_bsp_oclass = {
- .handle = NV_ENGINE(BSP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_bsp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nvc0_bsp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
deleted file mode 100644
index d4f23bbd75b4..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 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
-
-struct nve0_bsp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * BSP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_bsp_sclass[] = {
- { 0x95b1, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PBSP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_bsp_cclass = {
- .handle = NV_ENGCTX(BSP, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PBSP engine/subdev functions
- ******************************************************************************/
-
-static int
-nve0_bsp_init(struct nouveau_object *object)
-{
- struct nve0_bsp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x084010, 0x0000fff2);
- nv_wr32(priv, 0x08401c, 0x0000fff2);
- return 0;
-}
-
-static int
-nve0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_bsp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
- "PBSP", "bsp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00008000;
- nv_engine(priv)->cclass = &nve0_bsp_cclass;
- nv_engine(priv)->sclass = nve0_bsp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nve0_bsp_oclass = {
- .handle = NV_ENGINE(BSP, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_bsp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nve0_bsp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c b/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
index 283248c7b050..4df6da0af740 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
@@ -22,9 +22,10 @@
* Authors: Ben Skeggs
*/
-#include
-#include
+#include
#include
+#include
+#include
#include
#include
@@ -35,7 +36,11 @@
#include "fuc/nva3.fuc.h"
struct nva3_copy_priv {
- struct nouveau_falcon base;
+ struct nouveau_copy base;
+};
+
+struct nva3_copy_chan {
+ struct nouveau_copy_chan base;
};
/*******************************************************************************
@@ -52,16 +57,34 @@ nva3_copy_sclass[] = {
* PCOPY context
******************************************************************************/
+static int
+nva3_copy_context_ctor(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nva3_copy_chan *priv;
+ int ret;
+
+ ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256, 0,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static struct nouveau_oclass
nva3_copy_cclass = {
.handle = NV_ENGCTX(COPY0, 0xa3),
.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
+ .ctor = nva3_copy_context_ctor,
+ .dtor = _nouveau_copy_context_dtor,
+ .init = _nouveau_copy_context_init,
+ .fini = _nouveau_copy_context_fini,
+ .rd32 = _nouveau_copy_context_rd32,
+ .wr32 = _nouveau_copy_context_wr32,
},
};
@@ -77,40 +100,41 @@ static const struct nouveau_enum nva3_copy_isr_error_name[] = {
{}
};
-void
+static void
nva3_copy_intr(struct nouveau_subdev *subdev)
{
struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
struct nouveau_engine *engine = nv_engine(subdev);
- struct nouveau_falcon *falcon = (void *)subdev;
struct nouveau_object *engctx;
- u32 dispatch = nv_ro32(falcon, 0x01c);
- u32 stat = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
- u64 inst = nv_ro32(falcon, 0x050) & 0x3fffffff;
- u32 ssta = nv_ro32(falcon, 0x040) & 0x0000ffff;
- u32 addr = nv_ro32(falcon, 0x040) >> 16;
+ struct nva3_copy_priv *priv = (void *)subdev;
+ u32 dispatch = nv_rd32(priv, 0x10401c);
+ u32 stat = nv_rd32(priv, 0x104008) & dispatch & ~(dispatch >> 16);
+ u64 inst = nv_rd32(priv, 0x104050) & 0x3fffffff;
+ u32 ssta = nv_rd32(priv, 0x104040) & 0x0000ffff;
+ u32 addr = nv_rd32(priv, 0x104040) >> 16;
u32 mthd = (addr & 0x07ff) << 2;
u32 subc = (addr & 0x3800) >> 11;
- u32 data = nv_ro32(falcon, 0x044);
+ u32 data = nv_rd32(priv, 0x104044);
int chid;
engctx = nouveau_engctx_get(engine, inst);
chid = pfifo->chid(pfifo, engctx);
if (stat & 0x00000040) {
- nv_error(falcon, "DISPATCH_ERROR [");
+ nv_error(priv, "DISPATCH_ERROR [");
nouveau_enum_print(nva3_copy_isr_error_name, ssta);
printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
chid, inst << 12, subc, mthd, data);
- nv_wo32(falcon, 0x004, 0x00000040);
+ nv_wr32(priv, 0x104004, 0x00000040);
stat &= ~0x00000040;
}
if (stat) {
- nv_error(falcon, "unhandled intr 0x%08x\n", stat);
- nv_wo32(falcon, 0x004, stat);
+ nv_error(priv, "unhandled intr 0x%08x\n", stat);
+ nv_wr32(priv, 0x104004, stat);
}
+ nv50_fb_trap(nouveau_fb(priv), 1);
nouveau_engctx_put(engctx);
}
@@ -130,8 +154,7 @@ nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nva3_copy_priv *priv;
int ret;
- ret = nouveau_falcon_create(parent, engine, oclass, 0x104000, enable,
- "PCE0", "copy0", &priv);
+ ret = nouveau_copy_create(parent, engine, oclass, enable, 0, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
@@ -141,22 +164,59 @@ nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_engine(priv)->cclass = &nva3_copy_cclass;
nv_engine(priv)->sclass = nva3_copy_sclass;
nv_engine(priv)->tlb_flush = nva3_copy_tlb_flush;
- nv_falcon(priv)->code.data = nva3_pcopy_code;
- nv_falcon(priv)->code.size = sizeof(nva3_pcopy_code);
- nv_falcon(priv)->data.data = nva3_pcopy_data;
- nv_falcon(priv)->data.size = sizeof(nva3_pcopy_data);
return 0;
}
+static int
+nva3_copy_init(struct nouveau_object *object)
+{
+ struct nva3_copy_priv *priv = (void *)object;
+ int ret, i;
+
+ ret = nouveau_copy_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* disable all interrupts */
+ nv_wr32(priv, 0x104014, 0xffffffff);
+
+ /* upload ucode */
+ nv_wr32(priv, 0x1041c0, 0x01000000);
+ for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
+ nv_wr32(priv, 0x1041c4, nva3_pcopy_data[i]);
+
+ nv_wr32(priv, 0x104180, 0x01000000);
+ for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(priv, 0x104188, i >> 6);
+ nv_wr32(priv, 0x104184, nva3_pcopy_code[i]);
+ }
+
+ /* start it running */
+ nv_wr32(priv, 0x10410c, 0x00000000);
+ nv_wr32(priv, 0x104104, 0x00000000); /* ENTRY */
+ nv_wr32(priv, 0x104100, 0x00000002); /* TRIGGER */
+ return 0;
+}
+
+static int
+nva3_copy_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nva3_copy_priv *priv = (void *)object;
+
+ nv_mask(priv, 0x104048, 0x00000003, 0x00000000);
+ nv_wr32(priv, 0x104014, 0xffffffff);
+
+ return nouveau_copy_fini(&priv->base, suspend);
+}
+
struct nouveau_oclass
nva3_copy_oclass = {
.handle = NV_ENGINE(COPY0, 0xa3),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nva3_copy_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = _nouveau_falcon_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
+ .dtor = _nouveau_copy_dtor,
+ .init = nva3_copy_init,
+ .fini = nva3_copy_fini,
},
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
index b3ed2737e21f..06d4a8791055 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
@@ -22,9 +22,10 @@
* Authors: Ben Skeggs
*/
-#include
-#include
+#include
#include
+#include
+#include
#include
#include
@@ -32,7 +33,11 @@
#include "fuc/nvc0.fuc.h"
struct nvc0_copy_priv {
- struct nouveau_falcon base;
+ struct nouveau_copy base;
+};
+
+struct nvc0_copy_chan {
+ struct nouveau_copy_chan base;
};
/*******************************************************************************
@@ -55,14 +60,32 @@ nvc0_copy1_sclass[] = {
* PCOPY context
******************************************************************************/
+static int
+nvc0_copy_context_ctor(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nvc0_copy_chan *priv;
+ int ret;
+
+ ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256,
+ 256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static struct nouveau_ofuncs
nvc0_copy_context_ofuncs = {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
+ .ctor = nvc0_copy_context_ctor,
+ .dtor = _nouveau_copy_context_dtor,
+ .init = _nouveau_copy_context_init,
+ .fini = _nouveau_copy_context_fini,
+ .rd32 = _nouveau_copy_context_rd32,
+ .wr32 = _nouveau_copy_context_wr32,
};
static struct nouveau_oclass
@@ -81,18 +104,50 @@ nvc0_copy1_cclass = {
* PCOPY engine/subdev functions
******************************************************************************/
-static int
-nvc0_copy_init(struct nouveau_object *object)
+static const struct nouveau_enum nvc0_copy_isr_error_name[] = {
+ { 0x0001, "ILLEGAL_MTHD" },
+ { 0x0002, "INVALID_ENUM" },
+ { 0x0003, "INVALID_BITFIELD" },
+ {}
+};
+
+static void
+nvc0_copy_intr(struct nouveau_subdev *subdev)
{
- struct nvc0_copy_priv *priv = (void *)object;
- int ret;
+ struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
+ struct nouveau_engine *engine = nv_engine(subdev);
+ struct nouveau_object *engctx;
+ int idx = nv_engidx(nv_object(subdev)) - NVDEV_ENGINE_COPY0;
+ struct nvc0_copy_priv *priv = (void *)subdev;
+ u32 disp = nv_rd32(priv, 0x10401c + (idx * 0x1000));
+ u32 intr = nv_rd32(priv, 0x104008 + (idx * 0x1000));
+ u32 stat = intr & disp & ~(disp >> 16);
+ u64 inst = nv_rd32(priv, 0x104050 + (idx * 0x1000)) & 0x0fffffff;
+ u32 ssta = nv_rd32(priv, 0x104040 + (idx * 0x1000)) & 0x0000ffff;
+ u32 addr = nv_rd32(priv, 0x104040 + (idx * 0x1000)) >> 16;
+ u32 mthd = (addr & 0x07ff) << 2;
+ u32 subc = (addr & 0x3800) >> 11;
+ u32 data = nv_rd32(priv, 0x104044 + (idx * 0x1000));
+ int chid;
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
+ engctx = nouveau_engctx_get(engine, inst);
+ chid = pfifo->chid(pfifo, engctx);
- nv_wo32(priv, 0x084, nv_engidx(object) - NVDEV_ENGINE_COPY0);
- return 0;
+ if (stat & 0x00000040) {
+ nv_error(priv, "DISPATCH_ERROR [");
+ nouveau_enum_print(nvc0_copy_isr_error_name, ssta);
+ printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
+ chid, (u64)inst << 12, subc, mthd, data);
+ nv_wr32(priv, 0x104004 + (idx * 0x1000), 0x00000040);
+ stat &= ~0x00000040;
+ }
+
+ if (stat) {
+ nv_error(priv, "unhandled intr 0x%08x\n", stat);
+ nv_wr32(priv, 0x104004 + (idx * 0x1000), stat);
+ }
+
+ nouveau_engctx_put(engctx);
}
static int
@@ -106,20 +161,15 @@ nvc0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (nv_rd32(parent, 0x022500) & 0x00000100)
return -ENODEV;
- ret = nouveau_falcon_create(parent, engine, oclass, 0x104000, true,
- "PCE0", "copy0", &priv);
+ ret = nouveau_copy_create(parent, engine, oclass, true, 0, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000040;
- nv_subdev(priv)->intr = nva3_copy_intr;
+ nv_subdev(priv)->intr = nvc0_copy_intr;
nv_engine(priv)->cclass = &nvc0_copy0_cclass;
nv_engine(priv)->sclass = nvc0_copy0_sclass;
- nv_falcon(priv)->code.data = nvc0_pcopy_code;
- nv_falcon(priv)->code.size = sizeof(nvc0_pcopy_code);
- nv_falcon(priv)->data.data = nvc0_pcopy_data;
- nv_falcon(priv)->data.size = sizeof(nvc0_pcopy_data);
return 0;
}
@@ -134,33 +184,72 @@ nvc0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (nv_rd32(parent, 0x022500) & 0x00000200)
return -ENODEV;
- ret = nouveau_falcon_create(parent, engine, oclass, 0x105000, true,
- "PCE1", "copy1", &priv);
+ ret = nouveau_copy_create(parent, engine, oclass, true, 1, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000080;
- nv_subdev(priv)->intr = nva3_copy_intr;
+ nv_subdev(priv)->intr = nvc0_copy_intr;
nv_engine(priv)->cclass = &nvc0_copy1_cclass;
nv_engine(priv)->sclass = nvc0_copy1_sclass;
- nv_falcon(priv)->code.data = nvc0_pcopy_code;
- nv_falcon(priv)->code.size = sizeof(nvc0_pcopy_code);
- nv_falcon(priv)->data.data = nvc0_pcopy_data;
- nv_falcon(priv)->data.size = sizeof(nvc0_pcopy_data);
return 0;
}
+static int
+nvc0_copy_init(struct nouveau_object *object)
+{
+ int idx = nv_engidx(object) - NVDEV_ENGINE_COPY0;
+ struct nvc0_copy_priv *priv = (void *)object;
+ int ret, i;
+
+ ret = nouveau_copy_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* disable all interrupts */
+ nv_wr32(priv, 0x104014 + (idx * 0x1000), 0xffffffff);
+
+ /* upload ucode */
+ nv_wr32(priv, 0x1041c0 + (idx * 0x1000), 0x01000000);
+ for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
+ nv_wr32(priv, 0x1041c4 + (idx * 0x1000), nvc0_pcopy_data[i]);
+
+ nv_wr32(priv, 0x104180 + (idx * 0x1000), 0x01000000);
+ for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(priv, 0x104188 + (idx * 0x1000), i >> 6);
+ nv_wr32(priv, 0x104184 + (idx * 0x1000), nvc0_pcopy_code[i]);
+ }
+
+ /* start it running */
+ nv_wr32(priv, 0x104084 + (idx * 0x1000), idx);
+ nv_wr32(priv, 0x10410c + (idx * 0x1000), 0x00000000);
+ nv_wr32(priv, 0x104104 + (idx * 0x1000), 0x00000000); /* ENTRY */
+ nv_wr32(priv, 0x104100 + (idx * 0x1000), 0x00000002); /* TRIGGER */
+ return 0;
+}
+
+static int
+nvc0_copy_fini(struct nouveau_object *object, bool suspend)
+{
+ int idx = nv_engidx(object) - NVDEV_ENGINE_COPY0;
+ struct nvc0_copy_priv *priv = (void *)object;
+
+ nv_mask(priv, 0x104048 + (idx * 0x1000), 0x00000003, 0x00000000);
+ nv_wr32(priv, 0x104014 + (idx * 0x1000), 0xffffffff);
+
+ return nouveau_copy_fini(&priv->base, suspend);
+}
+
struct nouveau_oclass
nvc0_copy0_oclass = {
.handle = NV_ENGINE(COPY0, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_copy0_ctor,
- .dtor = _nouveau_falcon_dtor,
+ .dtor = _nouveau_copy_dtor,
.init = nvc0_copy_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
+ .fini = nvc0_copy_fini,
},
};
@@ -169,10 +258,8 @@ nvc0_copy1_oclass = {
.handle = NV_ENGINE(COPY1, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_copy1_ctor,
- .dtor = _nouveau_falcon_dtor,
+ .dtor = _nouveau_copy_dtor,
.init = nvc0_copy_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
+ .fini = nvc0_copy_fini,
},
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
index dbbe9e8998fe..2017c1579ac5 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
@@ -30,7 +30,11 @@
#include
struct nve0_copy_priv {
- struct nouveau_engine base;
+ struct nouveau_copy base;
+};
+
+struct nve0_copy_chan {
+ struct nouveau_copy_chan base;
};
/*******************************************************************************
@@ -47,14 +51,32 @@ nve0_copy_sclass[] = {
* PCOPY context
******************************************************************************/
+static int
+nve0_copy_context_ctor(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nve0_copy_chan *priv;
+ int ret;
+
+ ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256,
+ 256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static struct nouveau_ofuncs
nve0_copy_context_ofuncs = {
- .ctor = _nouveau_engctx_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
+ .ctor = nve0_copy_context_ctor,
+ .dtor = _nouveau_copy_context_dtor,
+ .init = _nouveau_copy_context_init,
+ .fini = _nouveau_copy_context_fini,
+ .rd32 = _nouveau_copy_context_rd32,
+ .wr32 = _nouveau_copy_context_wr32,
};
static struct nouveau_oclass
@@ -78,8 +100,7 @@ nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (nv_rd32(parent, 0x022500) & 0x00000100)
return -ENODEV;
- ret = nouveau_engine_create(parent, engine, oclass, true,
- "PCE0", "copy0", &priv);
+ ret = nouveau_copy_create(parent, engine, oclass, true, 0, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
@@ -101,8 +122,7 @@ nve0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (nv_rd32(parent, 0x022500) & 0x00000200)
return -ENODEV;
- ret = nouveau_engine_create(parent, engine, oclass, true,
- "PCE1", "copy1", &priv);
+ ret = nouveau_copy_create(parent, engine, oclass, true, 1, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
@@ -118,9 +138,9 @@ nve0_copy0_oclass = {
.handle = NV_ENGINE(COPY0, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nve0_copy0_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = _nouveau_engine_init,
- .fini = _nouveau_engine_fini,
+ .dtor = _nouveau_copy_dtor,
+ .init = _nouveau_copy_init,
+ .fini = _nouveau_copy_fini,
},
};
@@ -129,8 +149,8 @@ nve0_copy1_oclass = {
.handle = NV_ENGINE(COPY1, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nve0_copy1_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = _nouveau_engine_init,
- .fini = _nouveau_engine_fini,
+ .dtor = _nouveau_copy_dtor,
+ .init = _nouveau_copy_init,
+ .fini = _nouveau_copy_fini,
},
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c b/trunk/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
index b97490512723..1d85e5b66ca0 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
@@ -34,7 +34,11 @@
#include
struct nv84_crypt_priv {
- struct nouveau_engine base;
+ struct nouveau_crypt base;
+};
+
+struct nv84_crypt_chan {
+ struct nouveau_crypt_chan base;
};
/*******************************************************************************
@@ -83,16 +87,34 @@ nv84_crypt_sclass[] = {
* PCRYPT context
******************************************************************************/
+static int
+nv84_crypt_context_ctor(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nv84_crypt_chan *priv;
+ int ret;
+
+ ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256,
+ 0, NVOBJ_FLAG_ZERO_ALLOC, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static struct nouveau_oclass
nv84_crypt_cclass = {
.handle = NV_ENGCTX(CRYPT, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_engctx_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
+ .ctor = nv84_crypt_context_ctor,
+ .dtor = _nouveau_crypt_context_dtor,
+ .init = _nouveau_crypt_context_init,
+ .fini = _nouveau_crypt_context_fini,
+ .rd32 = _nouveau_crypt_context_rd32,
+ .wr32 = _nouveau_crypt_context_wr32,
},
};
@@ -135,6 +157,7 @@ nv84_crypt_intr(struct nouveau_subdev *subdev)
nv_wr32(priv, 0x102130, stat);
nv_wr32(priv, 0x10200c, 0x10);
+ nv50_fb_trap(nouveau_fb(priv), 1);
nouveau_engctx_put(engctx);
}
@@ -153,8 +176,7 @@ nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv84_crypt_priv *priv;
int ret;
- ret = nouveau_engine_create(parent, engine, oclass, true,
- "PCRYPT", "crypt", &priv);
+ ret = nouveau_crypt_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
@@ -173,7 +195,7 @@ nv84_crypt_init(struct nouveau_object *object)
struct nv84_crypt_priv *priv = (void *)object;
int ret;
- ret = nouveau_engine_init(&priv->base);
+ ret = nouveau_crypt_init(&priv->base);
if (ret)
return ret;
@@ -188,8 +210,8 @@ nv84_crypt_oclass = {
.handle = NV_ENGINE(CRYPT, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_crypt_ctor,
- .dtor = _nouveau_engine_dtor,
+ .dtor = _nouveau_crypt_dtor,
.init = nv84_crypt_init,
- .fini = _nouveau_engine_fini,
+ .fini = _nouveau_crypt_fini,
},
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c b/trunk/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
index 21986f3bf0c8..9e3876c89b96 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
@@ -26,7 +26,6 @@
#include
#include
#include
-#include
#include
#include
@@ -37,7 +36,11 @@
#include "fuc/nv98.fuc.h"
struct nv98_crypt_priv {
- struct nouveau_falcon base;
+ struct nouveau_crypt base;
+};
+
+struct nv98_crypt_chan {
+ struct nouveau_crypt_chan base;
};
/*******************************************************************************
@@ -54,16 +57,34 @@ nv98_crypt_sclass[] = {
* PCRYPT context
******************************************************************************/
+static int
+nv98_crypt_context_ctor(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nv98_crypt_chan *priv;
+ int ret;
+
+ ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256,
+ 256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static struct nouveau_oclass
nv98_crypt_cclass = {
.handle = NV_ENGCTX(CRYPT, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
+ .ctor = nv98_crypt_context_ctor,
+ .dtor = _nouveau_crypt_context_dtor,
+ .init = _nouveau_crypt_context_init,
+ .fini = _nouveau_crypt_context_fini,
+ .rd32 = _nouveau_crypt_context_rd32,
+ .wr32 = _nouveau_crypt_context_wr32,
},
};
@@ -113,6 +134,7 @@ nv98_crypt_intr(struct nouveau_subdev *subdev)
nv_wr32(priv, 0x087004, stat);
}
+ nv50_fb_trap(nouveau_fb(priv), 1);
nouveau_engctx_put(engctx);
}
@@ -131,8 +153,7 @@ nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv98_crypt_priv *priv;
int ret;
- ret = nouveau_falcon_create(parent, engine, oclass, 0x087000, true,
- "PCRYPT", "crypt", &priv);
+ ret = nouveau_crypt_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
@@ -142,10 +163,36 @@ nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_engine(priv)->cclass = &nv98_crypt_cclass;
nv_engine(priv)->sclass = nv98_crypt_sclass;
nv_engine(priv)->tlb_flush = nv98_crypt_tlb_flush;
- nv_falcon(priv)->code.data = nv98_pcrypt_code;
- nv_falcon(priv)->code.size = sizeof(nv98_pcrypt_code);
- nv_falcon(priv)->data.data = nv98_pcrypt_data;
- nv_falcon(priv)->data.size = sizeof(nv98_pcrypt_data);
+ return 0;
+}
+
+static int
+nv98_crypt_init(struct nouveau_object *object)
+{
+ struct nv98_crypt_priv *priv = (void *)object;
+ int ret, i;
+
+ ret = nouveau_crypt_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* wait for exit interrupt to signal */
+ nv_wait(priv, 0x087008, 0x00000010, 0x00000010);
+ nv_wr32(priv, 0x087004, 0x00000010);
+
+ /* upload microcode code and data segments */
+ nv_wr32(priv, 0x087ff8, 0x00100000);
+ for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_code); i++)
+ nv_wr32(priv, 0x087ff4, nv98_pcrypt_code[i]);
+
+ nv_wr32(priv, 0x087ff8, 0x00000000);
+ for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++)
+ nv_wr32(priv, 0x087ff4, nv98_pcrypt_data[i]);
+
+ /* start it running */
+ nv_wr32(priv, 0x08710c, 0x00000000);
+ nv_wr32(priv, 0x087104, 0x00000000); /* ENTRY */
+ nv_wr32(priv, 0x087100, 0x00000002); /* TRIGGER */
return 0;
}
@@ -154,10 +201,8 @@ nv98_crypt_oclass = {
.handle = NV_ENGINE(CRYPT, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_crypt_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = _nouveau_falcon_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
+ .dtor = _nouveau_crypt_dtor,
+ .init = nv98_crypt_init,
+ .fini = _nouveau_crypt_fini,
},
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c
deleted file mode 100644
index d0817d94454c..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include
-#include
-#include
-
-#include "nv50.h"
-
-int
-nv50_dac_power(struct nv50_disp_priv *priv, int or, u32 data)
-{
- const u32 stat = (data & NV50_DISP_DAC_PWR_HSYNC) |
- (data & NV50_DISP_DAC_PWR_VSYNC) |
- (data & NV50_DISP_DAC_PWR_DATA) |
- (data & NV50_DISP_DAC_PWR_STATE);
- const u32 doff = (or * 0x800);
- nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
- nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
- nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
- return 0;
-}
-
-int
-nv50_dac_sense(struct nv50_disp_priv *priv, int or, u32 loadval)
-{
- const u32 doff = (or * 0x800);
- int load = -EINVAL;
- nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval);
- udelay(9500);
- nv_wr32(priv, 0x61a00c + doff, 0x80000000);
- load = (nv_rd32(priv, 0x61a00c + doff) & 0x38000000) >> 27;
- nv_wr32(priv, 0x61a00c + doff, 0x00000000);
- return load;
-}
-
-int
-nv50_dac_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- const u8 or = (mthd & NV50_DISP_DAC_MTHD_OR);
- u32 *data = args;
- int ret;
-
- if (size < sizeof(u32))
- return -EINVAL;
-
- switch (mthd & ~0x3f) {
- case NV50_DISP_DAC_PWR:
- ret = priv->dac.power(priv, or, data[0]);
- break;
- case NV50_DISP_DAC_LOAD:
- ret = priv->dac.sense(priv, or, data[0]);
- if (ret >= 0) {
- data[0] = ret;
- ret = 0;
- }
- break;
- default:
- BUG_ON(1);
- }
-
- return ret;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
deleted file mode 100644
index 373dbcc523b2..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include "nv50.h"
-
-int
-nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
-{
- const u32 soff = (or * 0x800);
- int i;
-
- if (data && data[0]) {
- for (i = 0; i < size; i++)
- nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[i]);
- nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
- } else
- if (data) {
- nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000001);
- } else {
- nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000);
- }
-
- return 0;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
deleted file mode 100644
index dc57e24fc1df..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include
-#include
-#include
-#include
-
-#include "nv50.h"
-
-int
-nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
-{
- const u32 soff = (or * 0x030);
- int i;
-
- if (data && data[0]) {
- for (i = 0; i < size; i++)
- nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[i]);
- nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
- } else
- if (data) {
- nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000001);
- } else {
- nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000);
- }
-
- return 0;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c
deleted file mode 100644
index 0d36bdc51417..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include "nv50.h"
-
-int
-nv84_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data)
-{
- const u32 hoff = (head * 0x800);
-
- if (!(data & NV84_DISP_SOR_HDMI_PWR_STATE_ON)) {
- nv_mask(priv, 0x6165a4 + hoff, 0x40000000, 0x00000000);
- nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
- nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
- return 0;
- }
-
- /* AVI InfoFrame */
- nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x616528 + hoff, 0x000d0282);
- nv_wr32(priv, 0x61652c + hoff, 0x0000006f);
- nv_wr32(priv, 0x616530 + hoff, 0x00000000);
- nv_wr32(priv, 0x616534 + hoff, 0x00000000);
- nv_wr32(priv, 0x616538 + hoff, 0x00000000);
- nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000001);
-
- /* Audio InfoFrame */
- nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x616508 + hoff, 0x000a0184);
- nv_wr32(priv, 0x61650c + hoff, 0x00000071);
- nv_wr32(priv, 0x616510 + hoff, 0x00000000);
- nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000001);
-
- /* ??? */
- nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
- nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
- nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
-
- /* HDMI_CTRL */
- nv_mask(priv, 0x6165a4 + hoff, 0x5f1f007f, data | 0x1f000000 /* ??? */);
- return 0;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
deleted file mode 100644
index f065fc248adf..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include "nv50.h"
-
-int
-nva3_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data)
-{
- const u32 soff = (or * 0x800);
-
- if (!(data & NV84_DISP_SOR_HDMI_PWR_STATE_ON)) {
- nv_mask(priv, 0x61c5a4 + soff, 0x40000000, 0x00000000);
- nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
- nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
- return 0;
- }
-
- /* AVI InfoFrame */
- nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x61c528 + soff, 0x000d0282);
- nv_wr32(priv, 0x61c52c + soff, 0x0000006f);
- nv_wr32(priv, 0x61c530 + soff, 0x00000000);
- nv_wr32(priv, 0x61c534 + soff, 0x00000000);
- nv_wr32(priv, 0x61c538 + soff, 0x00000000);
- nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000001);
-
- /* Audio InfoFrame */
- nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x61c508 + soff, 0x000a0184);
- nv_wr32(priv, 0x61c50c + soff, 0x00000071);
- nv_wr32(priv, 0x61c510 + soff, 0x00000000);
- nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000001);
-
- /* ??? */
- nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
- nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
- nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
-
- /* HDMI_CTRL */
- nv_mask(priv, 0x61c5a4 + soff, 0x5f1f007f, data | 0x1f000000 /* ??? */);
- return 0;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c
deleted file mode 100644
index 5151bb261832..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include "nv50.h"
-
-int
-nvd0_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data)
-{
- const u32 hoff = (head * 0x800);
-
- if (!(data & NV84_DISP_SOR_HDMI_PWR_STATE_ON)) {
- nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
- nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
- nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
- return 0;
- }
-
- /* AVI InfoFrame */
- nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x61671c + hoff, 0x000d0282);
- nv_wr32(priv, 0x616720 + hoff, 0x0000006f);
- nv_wr32(priv, 0x616724 + hoff, 0x00000000);
- nv_wr32(priv, 0x616728 + hoff, 0x00000000);
- nv_wr32(priv, 0x61672c + hoff, 0x00000000);
- nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000001);
-
- /* ??? InfoFrame? */
- nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x6167ac + hoff, 0x00000010);
- nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000001);
-
- /* HDMI_CTRL */
- nv_mask(priv, 0x616798 + hoff, 0x401f007f, data);
-
- /* NFI, audio doesn't work without it though.. */
- nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000);
- return 0;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index c6f80055e988..16a9afb1060b 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -22,740 +22,18 @@
* Authors: Ben Skeggs
*/
-#include
-#include
-#include
-#include
-
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO channel base class
- ******************************************************************************/
-
-int
-nv50_disp_chan_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int chid,
- int length, void **pobject)
-{
- struct nv50_disp_base *base = (void *)parent;
- struct nv50_disp_chan *chan;
- int ret;
-
- if (base->chan & (1 << chid))
- return -EBUSY;
- base->chan |= (1 << chid);
-
- ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
- (1ULL << NVDEV_ENGINE_DMAOBJ),
- length, pobject);
- chan = *pobject;
- if (ret)
- return ret;
-
- chan->chid = chid;
- return 0;
-}
-
-void
-nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
-{
- struct nv50_disp_base *base = (void *)nv_object(chan)->parent;
- base->chan &= ~(1 << chan->chid);
- nouveau_namedb_destroy(&chan->base);
-}
-
-u32
-nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_chan *chan = (void *)object;
- return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr);
-}
-
-void
-nv50_disp_chan_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_chan *chan = (void *)object;
- nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data);
-}
-
-/*******************************************************************************
- * EVO DMA channel base class
- ******************************************************************************/
-
-static int
-nv50_disp_dmac_object_attach(struct nouveau_object *parent,
- struct nouveau_object *object, u32 name)
-{
- struct nv50_disp_base *base = (void *)parent->parent;
- struct nv50_disp_chan *chan = (void *)parent;
- u32 addr = nv_gpuobj(object)->node->offset;
- u32 chid = chan->chid;
- u32 data = (chid << 28) | (addr << 10) | chid;
- return nouveau_ramht_insert(base->ramht, chid, name, data);
-}
-
-static void
-nv50_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
-{
- struct nv50_disp_base *base = (void *)parent->parent;
- nouveau_ramht_remove(base->ramht, cookie);
-}
-
-int
-nv50_disp_dmac_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 pushbuf, int chid,
- int length, void **pobject)
-{
- struct nv50_disp_dmac *dmac;
- int ret;
-
- ret = nv50_disp_chan_create_(parent, engine, oclass, chid,
- length, pobject);
- dmac = *pobject;
- if (ret)
- return ret;
-
- dmac->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
- if (!dmac->pushdma)
- return -ENOENT;
-
- switch (nv_mclass(dmac->pushdma)) {
- case 0x0002:
- case 0x003d:
- if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
- return -EINVAL;
-
- switch (dmac->pushdma->target) {
- case NV_MEM_TARGET_VRAM:
- dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
- break;
- case NV_MEM_TARGET_PCI_NOSNOOP:
- dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
- break;
- default:
- return -EINVAL;
- }
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-void
-nv50_disp_dmac_dtor(struct nouveau_object *object)
-{
- struct nv50_disp_dmac *dmac = (void *)object;
- nouveau_object_ref(NULL, (struct nouveau_object **)&dmac->pushdma);
- nv50_disp_chan_destroy(&dmac->base);
-}
-
-static int
-nv50_disp_dmac_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *dmac = (void *)object;
- int chid = dmac->base.chid;
- int ret;
-
- ret = nv50_disp_chan_init(&dmac->base);
- if (ret)
- return ret;
-
- /* enable error reporting */
- nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid);
-
- /* initialise channel for dma command submission */
- nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
- nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000);
- nv_wr32(priv, 0x61020c + (chid * 0x0010), chid);
- nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
- nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
- nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013);
-
- /* wait for it to go inactive */
- if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) {
- nv_error(dmac, "init timeout, 0x%08x\n",
- nv_rd32(priv, 0x610200 + (chid * 0x10)));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *dmac = (void *)object;
- int chid = dmac->base.chid;
-
- /* deactivate channel */
- nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
- nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
- if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) {
- nv_error(dmac, "fini timeout, 0x%08x\n",
- nv_rd32(priv, 0x610200 + (chid * 0x10)));
- if (suspend)
- return -EBUSY;
- }
-
- /* disable error reporting */
- nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
-
- return nv50_disp_chan_fini(&dmac->base, suspend);
-}
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-static int
-nv50_disp_mast_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_display_mast_class *args = data;
- struct nv50_disp_dmac *mast;
- int ret;
-
- if (size < sizeof(*args))
- return -EINVAL;
-
- ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
- 0, sizeof(*mast), (void **)&mast);
- *pobject = nv_object(mast);
- if (ret)
- return ret;
-
- nv_parent(mast)->object_attach = nv50_disp_dmac_object_attach;
- nv_parent(mast)->object_detach = nv50_disp_dmac_object_detach;
- return 0;
-}
-
-static int
-nv50_disp_mast_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *mast = (void *)object;
- int ret;
-
- ret = nv50_disp_chan_init(&mast->base);
- if (ret)
- return ret;
-
- /* enable error reporting */
- nv_mask(priv, 0x610028, 0x00010001, 0x00010001);
-
- /* attempt to unstick channel from some unknown state */
- if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
- nv_mask(priv, 0x610200, 0x00800000, 0x00800000);
- if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000)
- nv_mask(priv, 0x610200, 0x00600000, 0x00600000);
-
- /* initialise channel for dma command submission */
- nv_wr32(priv, 0x610204, mast->push);
- nv_wr32(priv, 0x610208, 0x00010000);
- nv_wr32(priv, 0x61020c, 0x00000000);
- nv_mask(priv, 0x610200, 0x00000010, 0x00000010);
- nv_wr32(priv, 0x640000, 0x00000000);
- nv_wr32(priv, 0x610200, 0x01000013);
-
- /* wait for it to go inactive */
- if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) {
- nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *mast = (void *)object;
-
- /* deactivate channel */
- nv_mask(priv, 0x610200, 0x00000010, 0x00000000);
- nv_mask(priv, 0x610200, 0x00000003, 0x00000000);
- if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) {
- nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200));
- if (suspend)
- return -EBUSY;
- }
-
- /* disable error reporting */
- nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
-
- return nv50_disp_chan_fini(&mast->base, suspend);
-}
-
-struct nouveau_ofuncs
-nv50_disp_mast_ofuncs = {
- .ctor = nv50_disp_mast_ctor,
- .dtor = nv50_disp_dmac_dtor,
- .init = nv50_disp_mast_init,
- .fini = nv50_disp_mast_fini,
- .rd32 = nv50_disp_chan_rd32,
- .wr32 = nv50_disp_chan_wr32,
-};
-
-/*******************************************************************************
- * EVO sync channel objects
- ******************************************************************************/
-
-static int
-nv50_disp_sync_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_display_sync_class *args = data;
- struct nv50_disp_dmac *dmac;
- int ret;
-
- if (size < sizeof(*data) || args->head > 1)
- return -EINVAL;
-
- ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
- 1 + args->head, sizeof(*dmac),
- (void **)&dmac);
- *pobject = nv_object(dmac);
- if (ret)
- return ret;
-
- nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach;
- nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach;
- return 0;
-}
-
-struct nouveau_ofuncs
-nv50_disp_sync_ofuncs = {
- .ctor = nv50_disp_sync_ctor,
- .dtor = nv50_disp_dmac_dtor,
- .init = nv50_disp_dmac_init,
- .fini = nv50_disp_dmac_fini,
- .rd32 = nv50_disp_chan_rd32,
- .wr32 = nv50_disp_chan_wr32,
-};
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-static int
-nv50_disp_ovly_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_display_ovly_class *args = data;
- struct nv50_disp_dmac *dmac;
- int ret;
-
- if (size < sizeof(*data) || args->head > 1)
- return -EINVAL;
-
- ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
- 3 + args->head, sizeof(*dmac),
- (void **)&dmac);
- *pobject = nv_object(dmac);
- if (ret)
- return ret;
-
- nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach;
- nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach;
- return 0;
-}
-
-struct nouveau_ofuncs
-nv50_disp_ovly_ofuncs = {
- .ctor = nv50_disp_ovly_ctor,
- .dtor = nv50_disp_dmac_dtor,
- .init = nv50_disp_dmac_init,
- .fini = nv50_disp_dmac_fini,
- .rd32 = nv50_disp_chan_rd32,
- .wr32 = nv50_disp_chan_wr32,
-};
-
-/*******************************************************************************
- * EVO PIO channel base class
- ******************************************************************************/
-
-static int
-nv50_disp_pioc_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int chid,
- int length, void **pobject)
-{
- return nv50_disp_chan_create_(parent, engine, oclass, chid,
- length, pobject);
-}
-
-static void
-nv50_disp_pioc_dtor(struct nouveau_object *object)
-{
- struct nv50_disp_pioc *pioc = (void *)object;
- nv50_disp_chan_destroy(&pioc->base);
-}
-
-static int
-nv50_disp_pioc_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_pioc *pioc = (void *)object;
- int chid = pioc->base.chid;
- int ret;
-
- ret = nv50_disp_chan_init(&pioc->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000);
- if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) {
- nv_error(pioc, "timeout0: 0x%08x\n",
- nv_rd32(priv, 0x610200 + (chid * 0x10)));
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001);
- if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) {
- nv_error(pioc, "timeout1: 0x%08x\n",
- nv_rd32(priv, 0x610200 + (chid * 0x10)));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_pioc *pioc = (void *)object;
- int chid = pioc->base.chid;
-
- nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
- if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) {
- nv_error(pioc, "timeout: 0x%08x\n",
- nv_rd32(priv, 0x610200 + (chid * 0x10)));
- if (suspend)
- return -EBUSY;
- }
-
- return nv50_disp_chan_fini(&pioc->base, suspend);
-}
-
-/*******************************************************************************
- * EVO immediate overlay channel objects
- ******************************************************************************/
-
-static int
-nv50_disp_oimm_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_display_oimm_class *args = data;
- struct nv50_disp_pioc *pioc;
- int ret;
-
- if (size < sizeof(*args) || args->head > 1)
- return -EINVAL;
-
- ret = nv50_disp_pioc_create_(parent, engine, oclass, 5 + args->head,
- sizeof(*pioc), (void **)&pioc);
- *pobject = nv_object(pioc);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_ofuncs
-nv50_disp_oimm_ofuncs = {
- .ctor = nv50_disp_oimm_ctor,
- .dtor = nv50_disp_pioc_dtor,
- .init = nv50_disp_pioc_init,
- .fini = nv50_disp_pioc_fini,
- .rd32 = nv50_disp_chan_rd32,
- .wr32 = nv50_disp_chan_wr32,
-};
-
-/*******************************************************************************
- * EVO cursor channel objects
- ******************************************************************************/
-
-static int
-nv50_disp_curs_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_display_curs_class *args = data;
- struct nv50_disp_pioc *pioc;
- int ret;
-
- if (size < sizeof(*args) || args->head > 1)
- return -EINVAL;
-
- ret = nv50_disp_pioc_create_(parent, engine, oclass, 7 + args->head,
- sizeof(*pioc), (void **)&pioc);
- *pobject = nv_object(pioc);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_ofuncs
-nv50_disp_curs_ofuncs = {
- .ctor = nv50_disp_curs_ctor,
- .dtor = nv50_disp_pioc_dtor,
- .init = nv50_disp_pioc_init,
- .fini = nv50_disp_pioc_fini,
- .rd32 = nv50_disp_chan_rd32,
- .wr32 = nv50_disp_chan_wr32,
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static int
-nv50_disp_base_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_base *base;
- int ret;
-
- ret = nouveau_parent_create(parent, engine, oclass, 0,
- priv->sclass, 0, &base);
- *pobject = nv_object(base);
- if (ret)
- return ret;
-
- return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht);
-}
-
-static void
-nv50_disp_base_dtor(struct nouveau_object *object)
-{
- struct nv50_disp_base *base = (void *)object;
- nouveau_ramht_ref(NULL, &base->ramht);
- nouveau_parent_destroy(&base->base);
-}
-
-static int
-nv50_disp_base_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_base *base = (void *)object;
- int ret, i;
- u32 tmp;
-
- ret = nouveau_parent_init(&base->base);
- if (ret)
- return ret;
-
- /* The below segments of code copying values from one register to
- * another appear to inform EVO of the display capabilities or
- * something similar. NFI what the 0x614004 caps are for..
- */
- tmp = nv_rd32(priv, 0x614004);
- nv_wr32(priv, 0x610184, tmp);
-
- /* ... CRTC caps */
- for (i = 0; i < priv->head.nr; i++) {
- tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
- nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
- tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
- nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
- tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
- nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
- tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
- nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
- }
-
- /* ... DAC caps */
- for (i = 0; i < priv->dac.nr; i++) {
- tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
- nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
- }
-
- /* ... SOR caps */
- for (i = 0; i < priv->sor.nr; i++) {
- tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
- nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
- }
-
- /* ... EXT caps */
- for (i = 0; i < 3; i++) {
- tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
- nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
- }
-
- /* steal display away from vbios, or something like that */
- if (nv_rd32(priv, 0x610024) & 0x00000100) {
- nv_wr32(priv, 0x610024, 0x00000100);
- nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
- if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
- nv_error(priv, "timeout acquiring display\n");
- return -EBUSY;
- }
- }
-
- /* point at display engine memory area (hash table, objects) */
- nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
-
- /* enable supervisor interrupts, disable everything else */
- nv_wr32(priv, 0x61002c, 0x00000370);
- nv_wr32(priv, 0x610028, 0x00000000);
- return 0;
-}
-
-static int
-nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_base *base = (void *)object;
-
- /* disable all interrupts */
- nv_wr32(priv, 0x610024, 0x00000000);
- nv_wr32(priv, 0x610020, 0x00000000);
-
- return nouveau_parent_fini(&base->base, suspend);
-}
-
-struct nouveau_ofuncs
-nv50_disp_base_ofuncs = {
- .ctor = nv50_disp_base_ctor,
- .dtor = nv50_disp_base_dtor,
- .init = nv50_disp_base_init,
- .fini = nv50_disp_base_fini,
-};
-
-static struct nouveau_omthds
-nv50_disp_base_omthds[] = {
- { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
- { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
- { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
- { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
- {},
-};
-
-static struct nouveau_oclass
-nv50_disp_base_oclass[] = {
- { NV50_DISP_CLASS, &nv50_disp_base_ofuncs, nv50_disp_base_omthds },
- {}
+struct nv50_disp_priv {
+ struct nouveau_disp base;
};
static struct nouveau_oclass
nv50_disp_sclass[] = {
- { NV50_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
- { NV50_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs },
- { NV50_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs },
- { NV50_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs },
- { NV50_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * Display context, tracks instmem allocation and prevents more than one
- * client using the display hardware at any time.
- ******************************************************************************/
-
-static int
-nv50_disp_data_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv = (void *)engine;
- struct nouveau_engctx *ectx;
- int ret = -EBUSY;
-
- /* no context needed for channel objects... */
- if (nv_mclass(parent) != NV_DEVICE_CLASS) {
- atomic_inc(&parent->refcount);
- *pobject = parent;
- return 0;
- }
-
- /* allocate display hardware to client */
- mutex_lock(&nv_subdev(priv)->mutex);
- if (list_empty(&nv_engine(priv)->contexts)) {
- ret = nouveau_engctx_create(parent, engine, oclass, NULL,
- 0x10000, 0x10000,
- NVOBJ_FLAG_HEAP, &ectx);
- *pobject = nv_object(ectx);
- }
- mutex_unlock(&nv_subdev(priv)->mutex);
- return ret;
-}
-
-struct nouveau_oclass
-nv50_disp_cclass = {
- .handle = NV_ENGCTX(DISP, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_disp_data_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
- },
+ {},
};
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static void
-nv50_disp_intr_error(struct nv50_disp_priv *priv)
-{
- u32 channels = (nv_rd32(priv, 0x610020) & 0x001f0000) >> 16;
- u32 addr, data;
- int chid;
-
- for (chid = 0; chid < 5; chid++) {
- if (!(channels & (1 << chid)))
- continue;
-
- nv_wr32(priv, 0x610020, 0x00010000 << chid);
- addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
- data = nv_rd32(priv, 0x610084 + (chid * 0x08));
- nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
-
- nv_error(priv, "chid %d mthd 0x%04x data 0x%08x 0x%08x\n",
- chid, addr & 0xffc, data, addr);
- }
-}
-
static void
nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
{
@@ -793,422 +71,30 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
disp->vblank.notify(disp->vblank.data, crtc);
}
-static u16
-exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
- struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *info)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- u16 mask, type, data;
-
- if (outp < 4) {
- type = DCB_OUTPUT_ANALOG;
- mask = 0;
- } else {
- outp -= 4;
- switch (ctrl & 0x00000f00) {
- case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
- case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
- case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
- case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
- case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
- case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
- default:
- nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
- return 0x0000;
- }
- }
-
- mask = 0x00c0 & (mask << 6);
- mask |= 0x0001 << outp;
- mask |= 0x0100 << head;
-
- data = dcb_outp_match(bios, type, mask, ver, hdr, dcb);
- if (!data)
- return 0x0000;
-
- return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info);
-}
-
-static bool
-exec_script(struct nv50_disp_priv *priv, int head, int id)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_outp info;
- struct dcb_output dcb;
- u8 ver, hdr, cnt, len;
- u16 data;
- u32 ctrl = 0x00000000;
- int i;
-
- for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
- ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
-
- if (nv_device(priv)->chipset < 0x90 ||
- nv_device(priv)->chipset == 0x92 ||
- nv_device(priv)->chipset == 0xa0) {
- for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
- ctrl = nv_rd32(priv, 0x610b74 + (i * 8));
- i += 3;
- } else {
- for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
- ctrl = nv_rd32(priv, 0x610798 + (i * 8));
- i += 3;
- }
-
- if (!(ctrl & (1 << head)))
- return false;
-
- data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
- if (data) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = info.script[id],
- .outp = &dcb,
- .crtc = head,
- .execute = 1,
- };
-
- return nvbios_exec(&init) == 0;
- }
-
- return false;
-}
-
-static u32
-exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
- struct dcb_output *outp)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_outp info1;
- struct nvbios_ocfg info2;
- u8 ver, hdr, cnt, len;
- u16 data, conf;
- u32 ctrl = 0x00000000;
- int i;
-
- for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
- ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
-
- if (nv_device(priv)->chipset < 0x90 ||
- nv_device(priv)->chipset == 0x92 ||
- nv_device(priv)->chipset == 0xa0) {
- for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
- ctrl = nv_rd32(priv, 0x610b70 + (i * 8));
- i += 3;
- } else {
- for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
- ctrl = nv_rd32(priv, 0x610794 + (i * 8));
- i += 3;
- }
-
- if (!(ctrl & (1 << head)))
- return 0x0000;
-
- data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1);
- if (!data)
- return 0x0000;
-
- switch (outp->type) {
- case DCB_OUTPUT_TMDS:
- conf = (ctrl & 0x00000f00) >> 8;
- if (pclk >= 165000)
- conf |= 0x0100;
- break;
- case DCB_OUTPUT_LVDS:
- conf = priv->sor.lvdsconf;
- break;
- case DCB_OUTPUT_DP:
- conf = (ctrl & 0x00000f00) >> 8;
- break;
- case DCB_OUTPUT_ANALOG:
- default:
- conf = 0x00ff;
- break;
- }
-
- data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
- if (data) {
- data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
- if (data) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = data,
- .outp = outp,
- .crtc = head,
- .execute = 1,
- };
-
- if (nvbios_exec(&init))
- return 0x0000;
- return conf;
- }
- }
-
- return 0x0000;
-}
-
-static void
-nv50_disp_intr_unk10(struct nv50_disp_priv *priv, u32 super)
-{
- int head = ffs((super & 0x00000060) >> 5) - 1;
- if (head >= 0) {
- head = ffs((super & 0x00000180) >> 7) - 1;
- if (head >= 0)
- exec_script(priv, head, 1);
- }
-
- nv_wr32(priv, 0x610024, 0x00000010);
- nv_wr32(priv, 0x610030, 0x80000000);
-}
-
-static void
-nv50_disp_intr_unk20_dp(struct nv50_disp_priv *priv,
- struct dcb_output *outp, u32 pclk)
-{
- const int link = !(outp->sorconf.link & 1);
- const int or = ffs(outp->or) - 1;
- const u32 soff = ( or * 0x800);
- const u32 loff = (link * 0x080) + soff;
- const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
- const u32 symbol = 100000;
- u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x0000f0000;
- u32 clksor = nv_rd32(priv, 0x614300 + soff);
- int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
- int TU, VTUi, VTUf, VTUa;
- u64 link_data_rate, link_ratio, unk;
- u32 best_diff = 64 * symbol;
- u32 link_nr, link_bw, bits, r;
-
- /* calculate packed data rate for each lane */
- if (dpctrl > 0x00030000) link_nr = 4;
- else if (dpctrl > 0x00010000) link_nr = 2;
- else link_nr = 1;
-
- if (clksor & 0x000c0000)
- link_bw = 270000;
- else
- link_bw = 162000;
-
- if ((ctrl & 0xf0000) == 0x60000) bits = 30;
- else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
- else bits = 18;
-
- link_data_rate = (pclk * bits / 8) / link_nr;
-
- /* calculate ratio of packed data rate to link symbol rate */
- link_ratio = link_data_rate * symbol;
- r = do_div(link_ratio, link_bw);
-
- for (TU = 64; TU >= 32; TU--) {
- /* calculate average number of valid symbols in each TU */
- u32 tu_valid = link_ratio * TU;
- u32 calc, diff;
-
- /* find a hw representation for the fraction.. */
- VTUi = tu_valid / symbol;
- calc = VTUi * symbol;
- diff = tu_valid - calc;
- if (diff) {
- if (diff >= (symbol / 2)) {
- VTUf = symbol / (symbol - diff);
- if (symbol - (VTUf * diff))
- VTUf++;
-
- if (VTUf <= 15) {
- VTUa = 1;
- calc += symbol - (symbol / VTUf);
- } else {
- VTUa = 0;
- VTUf = 1;
- calc += symbol;
- }
- } else {
- VTUa = 0;
- VTUf = min((int)(symbol / diff), 15);
- calc += symbol / VTUf;
- }
-
- diff = calc - tu_valid;
- } else {
- /* no remainder, but the hw doesn't like the fractional
- * part to be zero. decrement the integer part and
- * have the fraction add a whole symbol back
- */
- VTUa = 0;
- VTUf = 1;
- VTUi--;
- }
-
- if (diff < best_diff) {
- best_diff = diff;
- bestTU = TU;
- bestVTUa = VTUa;
- bestVTUf = VTUf;
- bestVTUi = VTUi;
- if (diff == 0)
- break;
- }
- }
-
- if (!bestTU) {
- nv_error(priv, "unable to find suitable dp config\n");
- return;
- }
-
- /* XXX close to vbios numbers, but not right */
- unk = (symbol - link_ratio) * bestTU;
- unk *= link_ratio;
- r = do_div(unk, symbol);
- r = do_div(unk, symbol);
- unk += 6;
-
- nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2);
- nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
- bestVTUf << 16 |
- bestVTUi << 8 | unk);
-}
-
-static void
-nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super)
-{
- struct dcb_output outp;
- u32 addr, mask, data;
- int head;
-
- /* finish detaching encoder? */
- head = ffs((super & 0x00000180) >> 7) - 1;
- if (head >= 0)
- exec_script(priv, head, 2);
-
- /* check whether a vpll change is required */
- head = ffs((super & 0x00000600) >> 9) - 1;
- if (head >= 0) {
- u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
- if (pclk) {
- struct nouveau_clock *clk = nouveau_clock(priv);
- clk->pll_set(clk, PLL_VPLL0 + head, pclk);
- }
-
- nv_mask(priv, 0x614200 + head * 0x800, 0x0000000f, 0x00000000);
- }
-
- /* (re)attach the relevant OR to the head */
- head = ffs((super & 0x00000180) >> 7) - 1;
- if (head >= 0) {
- u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
- u32 conf = exec_clkcmp(priv, head, 0, pclk, &outp);
- if (conf) {
- if (outp.type == DCB_OUTPUT_ANALOG) {
- addr = 0x614280 + (ffs(outp.or) - 1) * 0x800;
- mask = 0xffffffff;
- data = 0x00000000;
- } else {
- if (outp.type == DCB_OUTPUT_DP)
- nv50_disp_intr_unk20_dp(priv, &outp, pclk);
- addr = 0x614300 + (ffs(outp.or) - 1) * 0x800;
- mask = 0x00000707;
- data = (conf & 0x0100) ? 0x0101 : 0x0000;
- }
-
- nv_mask(priv, addr, mask, data);
- }
- }
-
- nv_wr32(priv, 0x610024, 0x00000020);
- nv_wr32(priv, 0x610030, 0x80000000);
-}
-
-/* If programming a TMDS output on a SOR that can also be configured for
- * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
- *
- * It looks like the VBIOS TMDS scripts make an attempt at this, however,
- * the VBIOS scripts on at least one board I have only switch it off on
- * link 0, causing a blank display if the output has previously been
- * programmed for DisplayPort.
- */
-static void
-nv50_disp_intr_unk40_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- const int link = !(outp->sorconf.link & 1);
- const int or = ffs(outp->or) - 1;
- const u32 loff = (or * 0x800) + (link * 0x80);
- const u16 mask = (outp->sorconf.link << 6) | outp->or;
- u8 ver, hdr;
-
- if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp))
- nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
-}
-
static void
-nv50_disp_intr_unk40(struct nv50_disp_priv *priv, u32 super)
-{
- int head = ffs((super & 0x00000180) >> 7) - 1;
- if (head >= 0) {
- struct dcb_output outp;
- u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
- if (pclk && exec_clkcmp(priv, head, 1, pclk, &outp)) {
- if (outp.type == DCB_OUTPUT_TMDS)
- nv50_disp_intr_unk40_tmds(priv, &outp);
- }
- }
-
- nv_wr32(priv, 0x610024, 0x00000040);
- nv_wr32(priv, 0x610030, 0x80000000);
-}
-
-static void
-nv50_disp_intr_super(struct nv50_disp_priv *priv, u32 intr1)
-{
- u32 super = nv_rd32(priv, 0x610030);
-
- nv_debug(priv, "supervisor 0x%08x 0x%08x\n", intr1, super);
-
- if (intr1 & 0x00000010)
- nv50_disp_intr_unk10(priv, super);
- if (intr1 & 0x00000020)
- nv50_disp_intr_unk20(priv, super);
- if (intr1 & 0x00000040)
- nv50_disp_intr_unk40(priv, super);
-}
-
-void
nv50_disp_intr(struct nouveau_subdev *subdev)
{
struct nv50_disp_priv *priv = (void *)subdev;
- u32 intr0 = nv_rd32(priv, 0x610020);
- u32 intr1 = nv_rd32(priv, 0x610024);
+ u32 stat1 = nv_rd32(priv, 0x610024);
- if (intr0 & 0x001f0000) {
- nv50_disp_intr_error(priv);
- intr0 &= ~0x001f0000;
- }
-
- if (intr1 & 0x00000004) {
+ if (stat1 & 0x00000004) {
nv50_disp_intr_vblank(priv, 0);
nv_wr32(priv, 0x610024, 0x00000004);
- intr1 &= ~0x00000004;
+ stat1 &= ~0x00000004;
}
- if (intr1 & 0x00000008) {
+ if (stat1 & 0x00000008) {
nv50_disp_intr_vblank(priv, 1);
nv_wr32(priv, 0x610024, 0x00000008);
- intr1 &= ~0x00000008;
+ stat1 &= ~0x00000008;
}
- if (intr1 & 0x00000070) {
- nv50_disp_intr_super(priv, intr1);
- intr1 &= ~0x00000070;
- }
}
static int
nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
{
struct nv50_disp_priv *priv;
int ret;
@@ -1219,16 +105,8 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- nv_engine(priv)->sclass = nv50_disp_base_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_engine(priv)->sclass = nv50_disp_sclass;
nv_subdev(priv)->intr = nv50_disp_intr;
- priv->sclass = nv50_disp_sclass;
- priv->head.nr = 2;
- priv->dac.nr = 3;
- priv->sor.nr = 2;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
INIT_LIST_HEAD(&priv->base.vblank.list);
spin_lock_init(&priv->base.vblank.lock);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
deleted file mode 100644
index a6bb931450f1..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
+++ /dev/null
@@ -1,142 +0,0 @@
-#ifndef __NV50_DISP_H__
-#define __NV50_DISP_H__
-
-#include
-#include
-#include
-
-#include
-#include
-
-struct dcb_output;
-
-struct nv50_disp_priv {
- struct nouveau_disp base;
- struct nouveau_oclass *sclass;
- struct {
- int nr;
- } head;
- struct {
- int nr;
- int (*power)(struct nv50_disp_priv *, int dac, u32 data);
- int (*sense)(struct nv50_disp_priv *, int dac, u32 load);
- } dac;
- struct {
- int nr;
- int (*power)(struct nv50_disp_priv *, int sor, u32 data);
- int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32);
- int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32);
- int (*dp_train_init)(struct nv50_disp_priv *, int sor, int link,
- int head, u16 type, u16 mask, u32 data,
- struct dcb_output *);
- int (*dp_train_fini)(struct nv50_disp_priv *, int sor, int link,
- int head, u16 type, u16 mask, u32 data,
- struct dcb_output *);
- int (*dp_train)(struct nv50_disp_priv *, int sor, int link,
- u16 type, u16 mask, u32 data,
- struct dcb_output *);
- int (*dp_lnkctl)(struct nv50_disp_priv *, int sor, int link,
- int head, u16 type, u16 mask, u32 data,
- struct dcb_output *);
- int (*dp_drvctl)(struct nv50_disp_priv *, int sor, int link,
- int lane, u16 type, u16 mask, u32 data,
- struct dcb_output *);
- u32 lvdsconf;
- } sor;
-};
-
-#define DAC_MTHD(n) (n), (n) + 0x03
-
-int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32);
-int nv50_dac_power(struct nv50_disp_priv *, int, u32);
-int nv50_dac_sense(struct nv50_disp_priv *, int, u32);
-
-#define SOR_MTHD(n) (n), (n) + 0x3f
-
-int nva3_hda_eld(struct nv50_disp_priv *, int, u8 *, u32);
-int nvd0_hda_eld(struct nv50_disp_priv *, int, u8 *, u32);
-
-int nv84_hdmi_ctrl(struct nv50_disp_priv *, int, int, u32);
-int nva3_hdmi_ctrl(struct nv50_disp_priv *, int, int, u32);
-int nvd0_hdmi_ctrl(struct nv50_disp_priv *, int, int, u32);
-
-int nv50_sor_mthd(struct nouveau_object *, u32, void *, u32);
-int nv50_sor_power(struct nv50_disp_priv *, int, u32);
-
-int nv94_sor_dp_train_init(struct nv50_disp_priv *, int, int, int, u16, u16,
- u32, struct dcb_output *);
-int nv94_sor_dp_train_fini(struct nv50_disp_priv *, int, int, int, u16, u16,
- u32, struct dcb_output *);
-int nv94_sor_dp_train(struct nv50_disp_priv *, int, int, u16, u16, u32,
- struct dcb_output *);
-int nv94_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
- struct dcb_output *);
-int nv94_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
- struct dcb_output *);
-
-int nvd0_sor_dp_train(struct nv50_disp_priv *, int, int, u16, u16, u32,
- struct dcb_output *);
-int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
- struct dcb_output *);
-int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
- struct dcb_output *);
-
-struct nv50_disp_base {
- struct nouveau_parent base;
- struct nouveau_ramht *ramht;
- u32 chan;
-};
-
-struct nv50_disp_chan {
- struct nouveau_namedb base;
- int chid;
-};
-
-int nv50_disp_chan_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, int, void **);
-void nv50_disp_chan_destroy(struct nv50_disp_chan *);
-u32 nv50_disp_chan_rd32(struct nouveau_object *, u64);
-void nv50_disp_chan_wr32(struct nouveau_object *, u64, u32);
-
-#define nv50_disp_chan_init(a) \
- nouveau_namedb_init(&(a)->base)
-#define nv50_disp_chan_fini(a,b) \
- nouveau_namedb_fini(&(a)->base, (b))
-
-int nv50_disp_dmac_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, u32, int, int, void **);
-void nv50_disp_dmac_dtor(struct nouveau_object *);
-
-struct nv50_disp_dmac {
- struct nv50_disp_chan base;
- struct nouveau_dmaobj *pushdma;
- u32 push;
-};
-
-struct nv50_disp_pioc {
- struct nv50_disp_chan base;
-};
-
-extern struct nouveau_ofuncs nv50_disp_mast_ofuncs;
-extern struct nouveau_ofuncs nv50_disp_sync_ofuncs;
-extern struct nouveau_ofuncs nv50_disp_ovly_ofuncs;
-extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs;
-extern struct nouveau_ofuncs nv50_disp_curs_ofuncs;
-extern struct nouveau_ofuncs nv50_disp_base_ofuncs;
-extern struct nouveau_oclass nv50_disp_cclass;
-void nv50_disp_intr(struct nouveau_subdev *);
-
-extern struct nouveau_omthds nv84_disp_base_omthds[];
-
-extern struct nouveau_omthds nva3_disp_base_omthds[];
-
-extern struct nouveau_ofuncs nvd0_disp_mast_ofuncs;
-extern struct nouveau_ofuncs nvd0_disp_sync_ofuncs;
-extern struct nouveau_ofuncs nvd0_disp_ovly_ofuncs;
-extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs;
-extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs;
-extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
-extern struct nouveau_oclass nvd0_disp_cclass;
-void nvd0_disp_intr(struct nouveau_subdev *);
-
-#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
deleted file mode 100644
index fc84eacdfbec..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include
-
-#include "nv50.h"
-
-static struct nouveau_oclass
-nv84_disp_sclass[] = {
- { NV84_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
- { NV84_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs },
- { NV84_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs },
- { NV84_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs },
- { NV84_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs },
- {}
-};
-
-struct nouveau_omthds
-nv84_disp_base_omthds[] = {
- { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
- { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
- { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
- { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
- { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
- {},
-};
-
-static struct nouveau_oclass
-nv84_disp_base_oclass[] = {
- { NV84_DISP_CLASS, &nv50_disp_base_ofuncs, nv84_disp_base_omthds },
- {}
-};
-
-static int
-nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nv84_disp_base_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nv50_disp_intr;
- priv->sclass = nv84_disp_sclass;
- priv->head.nr = 2;
- priv->dac.nr = 3;
- priv->sor.nr = 2;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hdmi = nv84_hdmi_ctrl;
-
- INIT_LIST_HEAD(&priv->base.vblank.list);
- spin_lock_init(&priv->base.vblank.lock);
- return 0;
-}
-
-struct nouveau_oclass
-nv84_disp_oclass = {
- .handle = NV_ENGINE(DISP, 0x82),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv84_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
deleted file mode 100644
index ba9dfd4669a2..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include
-
-#include "nv50.h"
-
-static struct nouveau_oclass
-nv94_disp_sclass[] = {
- { NV94_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
- { NV94_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs },
- { NV94_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs },
- { NV94_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs },
- { NV94_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs },
- {}
-};
-
-static struct nouveau_omthds
-nv94_disp_base_omthds[] = {
- { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
- { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
- { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_TRAIN) , nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_LNKCTL) , nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(0)), nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(1)), nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(2)), nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(3)), nv50_sor_mthd },
- { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
- { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
- {},
-};
-
-static struct nouveau_oclass
-nv94_disp_base_oclass[] = {
- { NV94_DISP_CLASS, &nv50_disp_base_ofuncs, nv94_disp_base_omthds },
- {}
-};
-
-static int
-nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nv94_disp_base_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nv50_disp_intr;
- priv->sclass = nv94_disp_sclass;
- priv->head.nr = 2;
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hdmi = nv84_hdmi_ctrl;
- priv->sor.dp_train = nv94_sor_dp_train;
- priv->sor.dp_train_init = nv94_sor_dp_train_init;
- priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
- priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl;
- priv->sor.dp_drvctl = nv94_sor_dp_drvctl;
-
- INIT_LIST_HEAD(&priv->base.vblank.list);
- spin_lock_init(&priv->base.vblank.lock);
- return 0;
-}
-
-struct nouveau_oclass
-nv94_disp_oclass = {
- .handle = NV_ENGINE(DISP, 0x88),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv94_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
deleted file mode 100644
index 5d63902cdeda..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include
-
-#include "nv50.h"
-
-static struct nouveau_oclass
-nva0_disp_sclass[] = {
- { NVA0_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
- { NVA0_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs },
- { NVA0_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs },
- { NVA0_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs },
- { NVA0_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs },
- {}
-};
-
-static struct nouveau_oclass
-nva0_disp_base_oclass[] = {
- { NVA0_DISP_CLASS, &nv50_disp_base_ofuncs, nv84_disp_base_omthds },
- {}
-};
-
-static int
-nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nva0_disp_base_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nv50_disp_intr;
- priv->sclass = nva0_disp_sclass;
- priv->head.nr = 2;
- priv->dac.nr = 3;
- priv->sor.nr = 2;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hdmi = nv84_hdmi_ctrl;
-
- INIT_LIST_HEAD(&priv->base.vblank.list);
- spin_lock_init(&priv->base.vblank.lock);
- return 0;
-}
-
-struct nouveau_oclass
-nva0_disp_oclass = {
- .handle = NV_ENGINE(DISP, 0x83),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nva0_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
deleted file mode 100644
index e9192ca389fa..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include
-
-#include "nv50.h"
-
-static struct nouveau_oclass
-nva3_disp_sclass[] = {
- { NVA3_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
- { NVA3_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs },
- { NVA3_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs },
- { NVA3_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs },
- { NVA3_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs },
- {}
-};
-
-struct nouveau_omthds
-nva3_disp_base_omthds[] = {
- { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
- { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd },
- { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
- { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_TRAIN) , nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_LNKCTL) , nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(0)), nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(1)), nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(2)), nv50_sor_mthd },
- { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(3)), nv50_sor_mthd },
- { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
- { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
- {},
-};
-
-static struct nouveau_oclass
-nva3_disp_base_oclass[] = {
- { NVA3_DISP_CLASS, &nv50_disp_base_ofuncs, nva3_disp_base_omthds },
- {}
-};
-
-static int
-nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nva3_disp_base_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nv50_disp_intr;
- priv->sclass = nva3_disp_sclass;
- priv->head.nr = 2;
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hda_eld = nva3_hda_eld;
- priv->sor.hdmi = nva3_hdmi_ctrl;
- priv->sor.dp_train = nv94_sor_dp_train;
- priv->sor.dp_train_init = nv94_sor_dp_train_init;
- priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
- priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl;
- priv->sor.dp_drvctl = nv94_sor_dp_drvctl;
-
- INIT_LIST_HEAD(&priv->base.vblank.list);
- spin_lock_init(&priv->base.vblank.lock);
- return 0;
-}
-
-struct nouveau_oclass
-nva3_disp_oclass = {
- .handle = NV_ENGINE(DISP, 0x85),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nva3_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
index 9e38ebff5fb3..d93efbcf75b8 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -22,808 +22,22 @@
* Authors: Ben Skeggs
*/
-#include
-#include
-#include
-#include
+#include
#include
#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO DMA channel base class
- ******************************************************************************/
-
-static int
-nvd0_disp_dmac_object_attach(struct nouveau_object *parent,
- struct nouveau_object *object, u32 name)
-{
- struct nv50_disp_base *base = (void *)parent->parent;
- struct nv50_disp_chan *chan = (void *)parent;
- u32 addr = nv_gpuobj(object)->node->offset;
- u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001;
- return nouveau_ramht_insert(base->ramht, chan->chid, name, data);
-}
-
-static void
-nvd0_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
-{
- struct nv50_disp_base *base = (void *)parent->parent;
- nouveau_ramht_remove(base->ramht, cookie);
-}
-
-static int
-nvd0_disp_dmac_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *dmac = (void *)object;
- int chid = dmac->base.chid;
- int ret;
-
- ret = nv50_disp_chan_init(&dmac->base);
- if (ret)
- return ret;
-
- /* enable error reporting */
- nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid);
- nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
-
- /* initialise channel for dma command submission */
- nv_wr32(priv, 0x610494 + (chid * 0x0010), dmac->push);
- nv_wr32(priv, 0x610498 + (chid * 0x0010), 0x00010000);
- nv_wr32(priv, 0x61049c + (chid * 0x0010), 0x00000001);
- nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010);
- nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
- nv_wr32(priv, 0x610490 + (chid * 0x0010), 0x00000013);
-
- /* wait for it to go inactive */
- if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) {
- nv_error(dmac, "init: 0x%08x\n",
- nv_rd32(priv, 0x610490 + (chid * 0x10)));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *dmac = (void *)object;
- int chid = dmac->base.chid;
-
- /* deactivate channel */
- nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000);
- nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000);
- if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) {
- nv_error(dmac, "fini: 0x%08x\n",
- nv_rd32(priv, 0x610490 + (chid * 0x10)));
- if (suspend)
- return -EBUSY;
- }
-
- /* disable error reporting */
- nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
- nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
-
- return nv50_disp_chan_fini(&dmac->base, suspend);
-}
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-static int
-nvd0_disp_mast_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_display_mast_class *args = data;
- struct nv50_disp_dmac *mast;
- int ret;
-
- if (size < sizeof(*args))
- return -EINVAL;
-
- ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
- 0, sizeof(*mast), (void **)&mast);
- *pobject = nv_object(mast);
- if (ret)
- return ret;
-
- nv_parent(mast)->object_attach = nvd0_disp_dmac_object_attach;
- nv_parent(mast)->object_detach = nvd0_disp_dmac_object_detach;
- return 0;
-}
-
-static int
-nvd0_disp_mast_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *mast = (void *)object;
- int ret;
-
- ret = nv50_disp_chan_init(&mast->base);
- if (ret)
- return ret;
-
- /* enable error reporting */
- nv_mask(priv, 0x610090, 0x00000001, 0x00000001);
- nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001);
-
- /* initialise channel for dma command submission */
- nv_wr32(priv, 0x610494, mast->push);
- nv_wr32(priv, 0x610498, 0x00010000);
- nv_wr32(priv, 0x61049c, 0x00000001);
- nv_mask(priv, 0x610490, 0x00000010, 0x00000010);
- nv_wr32(priv, 0x640000, 0x00000000);
- nv_wr32(priv, 0x610490, 0x01000013);
-
- /* wait for it to go inactive */
- if (!nv_wait(priv, 0x610490, 0x80000000, 0x00000000)) {
- nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610490));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *mast = (void *)object;
-
- /* deactivate channel */
- nv_mask(priv, 0x610490, 0x00000010, 0x00000000);
- nv_mask(priv, 0x610490, 0x00000003, 0x00000000);
- if (!nv_wait(priv, 0x610490, 0x001e0000, 0x00000000)) {
- nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610490));
- if (suspend)
- return -EBUSY;
- }
-
- /* disable error reporting */
- nv_mask(priv, 0x610090, 0x00000001, 0x00000000);
- nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000);
-
- return nv50_disp_chan_fini(&mast->base, suspend);
-}
-
-struct nouveau_ofuncs
-nvd0_disp_mast_ofuncs = {
- .ctor = nvd0_disp_mast_ctor,
- .dtor = nv50_disp_dmac_dtor,
- .init = nvd0_disp_mast_init,
- .fini = nvd0_disp_mast_fini,
- .rd32 = nv50_disp_chan_rd32,
- .wr32 = nv50_disp_chan_wr32,
-};
-
-/*******************************************************************************
- * EVO sync channel objects
- ******************************************************************************/
-
-static int
-nvd0_disp_sync_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_display_sync_class *args = data;
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_dmac *dmac;
- int ret;
-
- if (size < sizeof(*data) || args->head >= priv->head.nr)
- return -EINVAL;
-
- ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
- 1 + args->head, sizeof(*dmac),
- (void **)&dmac);
- *pobject = nv_object(dmac);
- if (ret)
- return ret;
-
- nv_parent(dmac)->object_attach = nvd0_disp_dmac_object_attach;
- nv_parent(dmac)->object_detach = nvd0_disp_dmac_object_detach;
- return 0;
-}
-
-struct nouveau_ofuncs
-nvd0_disp_sync_ofuncs = {
- .ctor = nvd0_disp_sync_ctor,
- .dtor = nv50_disp_dmac_dtor,
- .init = nvd0_disp_dmac_init,
- .fini = nvd0_disp_dmac_fini,
- .rd32 = nv50_disp_chan_rd32,
- .wr32 = nv50_disp_chan_wr32,
-};
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-static int
-nvd0_disp_ovly_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_display_ovly_class *args = data;
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_dmac *dmac;
- int ret;
-
- if (size < sizeof(*data) || args->head >= priv->head.nr)
- return -EINVAL;
-
- ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
- 5 + args->head, sizeof(*dmac),
- (void **)&dmac);
- *pobject = nv_object(dmac);
- if (ret)
- return ret;
-
- nv_parent(dmac)->object_attach = nvd0_disp_dmac_object_attach;
- nv_parent(dmac)->object_detach = nvd0_disp_dmac_object_detach;
- return 0;
-}
-
-struct nouveau_ofuncs
-nvd0_disp_ovly_ofuncs = {
- .ctor = nvd0_disp_ovly_ctor,
- .dtor = nv50_disp_dmac_dtor,
- .init = nvd0_disp_dmac_init,
- .fini = nvd0_disp_dmac_fini,
- .rd32 = nv50_disp_chan_rd32,
- .wr32 = nv50_disp_chan_wr32,
-};
-
-/*******************************************************************************
- * EVO PIO channel base class
- ******************************************************************************/
-
-static int
-nvd0_disp_pioc_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int chid,
- int length, void **pobject)
-{
- return nv50_disp_chan_create_(parent, engine, oclass, chid,
- length, pobject);
-}
-
-static void
-nvd0_disp_pioc_dtor(struct nouveau_object *object)
-{
- struct nv50_disp_pioc *pioc = (void *)object;
- nv50_disp_chan_destroy(&pioc->base);
-}
-
-static int
-nvd0_disp_pioc_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_pioc *pioc = (void *)object;
- int chid = pioc->base.chid;
- int ret;
-
- ret = nv50_disp_chan_init(&pioc->base);
- if (ret)
- return ret;
-
- /* enable error reporting */
- nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid);
- nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
-
- /* activate channel */
- nv_wr32(priv, 0x610490 + (chid * 0x10), 0x00000001);
- if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) {
- nv_error(pioc, "init: 0x%08x\n",
- nv_rd32(priv, 0x610490 + (chid * 0x10)));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nvd0_disp_pioc_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_pioc *pioc = (void *)object;
- int chid = pioc->base.chid;
-
- nv_mask(priv, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000);
- if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) {
- nv_error(pioc, "timeout: 0x%08x\n",
- nv_rd32(priv, 0x610490 + (chid * 0x10)));
- if (suspend)
- return -EBUSY;
- }
-
- /* disable error reporting */
- nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
- nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
-
- return nv50_disp_chan_fini(&pioc->base, suspend);
-}
-
-/*******************************************************************************
- * EVO immediate overlay channel objects
- ******************************************************************************/
-
-static int
-nvd0_disp_oimm_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_display_oimm_class *args = data;
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_pioc *pioc;
- int ret;
-
- if (size < sizeof(*args) || args->head >= priv->head.nr)
- return -EINVAL;
-
- ret = nvd0_disp_pioc_create_(parent, engine, oclass, 9 + args->head,
- sizeof(*pioc), (void **)&pioc);
- *pobject = nv_object(pioc);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_ofuncs
-nvd0_disp_oimm_ofuncs = {
- .ctor = nvd0_disp_oimm_ctor,
- .dtor = nvd0_disp_pioc_dtor,
- .init = nvd0_disp_pioc_init,
- .fini = nvd0_disp_pioc_fini,
- .rd32 = nv50_disp_chan_rd32,
- .wr32 = nv50_disp_chan_wr32,
-};
-
-/*******************************************************************************
- * EVO cursor channel objects
- ******************************************************************************/
-
-static int
-nvd0_disp_curs_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_display_curs_class *args = data;
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_pioc *pioc;
- int ret;
-
- if (size < sizeof(*args) || args->head >= priv->head.nr)
- return -EINVAL;
-
- ret = nvd0_disp_pioc_create_(parent, engine, oclass, 13 + args->head,
- sizeof(*pioc), (void **)&pioc);
- *pobject = nv_object(pioc);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_ofuncs
-nvd0_disp_curs_ofuncs = {
- .ctor = nvd0_disp_curs_ctor,
- .dtor = nvd0_disp_pioc_dtor,
- .init = nvd0_disp_pioc_init,
- .fini = nvd0_disp_pioc_fini,
- .rd32 = nv50_disp_chan_rd32,
- .wr32 = nv50_disp_chan_wr32,
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static int
-nvd0_disp_base_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_base *base;
- int ret;
-
- ret = nouveau_parent_create(parent, engine, oclass, 0,
- priv->sclass, 0, &base);
- *pobject = nv_object(base);
- if (ret)
- return ret;
-
- return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht);
-}
-
-static void
-nvd0_disp_base_dtor(struct nouveau_object *object)
-{
- struct nv50_disp_base *base = (void *)object;
- nouveau_ramht_ref(NULL, &base->ramht);
- nouveau_parent_destroy(&base->base);
-}
-
-static int
-nvd0_disp_base_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_base *base = (void *)object;
- int ret, i;
- u32 tmp;
-
- ret = nouveau_parent_init(&base->base);
- if (ret)
- return ret;
-
- /* The below segments of code copying values from one register to
- * another appear to inform EVO of the display capabilities or
- * something similar.
- */
-
- /* ... CRTC caps */
- for (i = 0; i < priv->head.nr; i++) {
- tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
- nv_wr32(priv, 0x6101b4 + (i * 0x800), tmp);
- tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
- nv_wr32(priv, 0x6101b8 + (i * 0x800), tmp);
- tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
- nv_wr32(priv, 0x6101bc + (i * 0x800), tmp);
- }
-
- /* ... DAC caps */
- for (i = 0; i < priv->dac.nr; i++) {
- tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
- nv_wr32(priv, 0x6101c0 + (i * 0x800), tmp);
- }
-
- /* ... SOR caps */
- for (i = 0; i < priv->sor.nr; i++) {
- tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
- nv_wr32(priv, 0x6301c4 + (i * 0x800), tmp);
- }
-
- /* steal display away from vbios, or something like that */
- if (nv_rd32(priv, 0x6100ac) & 0x00000100) {
- nv_wr32(priv, 0x6100ac, 0x00000100);
- nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
- if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
- nv_error(priv, "timeout acquiring display\n");
- return -EBUSY;
- }
- }
-
- /* point at display engine memory area (hash table, objects) */
- nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9);
-
- /* enable supervisor interrupts, disable everything else */
- nv_wr32(priv, 0x610090, 0x00000000);
- nv_wr32(priv, 0x6100a0, 0x00000000);
- nv_wr32(priv, 0x6100b0, 0x00000307);
-
- return 0;
-}
-
-static int
-nvd0_disp_base_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_base *base = (void *)object;
-
- /* disable all interrupts */
- nv_wr32(priv, 0x6100b0, 0x00000000);
-
- return nouveau_parent_fini(&base->base, suspend);
-}
-
-struct nouveau_ofuncs
-nvd0_disp_base_ofuncs = {
- .ctor = nvd0_disp_base_ctor,
- .dtor = nvd0_disp_base_dtor,
- .init = nvd0_disp_base_init,
- .fini = nvd0_disp_base_fini,
-};
-
-static struct nouveau_oclass
-nvd0_disp_base_oclass[] = {
- { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
- {}
+struct nvd0_disp_priv {
+ struct nouveau_disp base;
};
static struct nouveau_oclass
nvd0_disp_sclass[] = {
- { NVD0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs },
- { NVD0_DISP_SYNC_CLASS, &nvd0_disp_sync_ofuncs },
- { NVD0_DISP_OVLY_CLASS, &nvd0_disp_ovly_ofuncs },
- { NVD0_DISP_OIMM_CLASS, &nvd0_disp_oimm_ofuncs },
- { NVD0_DISP_CURS_CLASS, &nvd0_disp_curs_ofuncs },
- {}
+ {},
};
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static u16
-exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
- struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *info)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- u16 mask, type, data;
-
- if (outp < 4) {
- type = DCB_OUTPUT_ANALOG;
- mask = 0;
- } else {
- outp -= 4;
- switch (ctrl & 0x00000f00) {
- case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
- case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
- case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
- case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
- case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
- case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
- default:
- nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
- return 0x0000;
- }
- dcb->sorconf.link = mask;
- }
-
- mask = 0x00c0 & (mask << 6);
- mask |= 0x0001 << outp;
- mask |= 0x0100 << head;
-
- data = dcb_outp_match(bios, type, mask, ver, hdr, dcb);
- if (!data)
- return 0x0000;
-
- return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info);
-}
-
-static bool
-exec_script(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, int id)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_outp info;
- struct dcb_output dcb;
- u8 ver, hdr, cnt, len;
- u16 data;
-
- data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
- if (data) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = info.script[id],
- .outp = &dcb,
- .crtc = head,
- .execute = 1,
- };
-
- return nvbios_exec(&init) == 0;
- }
-
- return false;
-}
-
-static u32
-exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp,
- u32 ctrl, int id, u32 pclk)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_outp info1;
- struct nvbios_ocfg info2;
- struct dcb_output dcb;
- u8 ver, hdr, cnt, len;
- u16 data, conf;
-
- data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info1);
- if (data == 0x0000)
- return false;
-
- switch (dcb.type) {
- case DCB_OUTPUT_TMDS:
- conf = (ctrl & 0x00000f00) >> 8;
- if (pclk >= 165000)
- conf |= 0x0100;
- break;
- case DCB_OUTPUT_LVDS:
- conf = priv->sor.lvdsconf;
- break;
- case DCB_OUTPUT_DP:
- conf = (ctrl & 0x00000f00) >> 8;
- break;
- case DCB_OUTPUT_ANALOG:
- default:
- conf = 0x00ff;
- break;
- }
-
- data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
- if (data) {
- data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
- if (data) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = data,
- .outp = &dcb,
- .crtc = head,
- .execute = 1,
- };
-
- if (nvbios_exec(&init))
- return 0x0000;
- return conf;
- }
- }
-
- return 0x0000;
-}
-
-static void
-nvd0_display_unk1_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
-{
- int i;
-
- for (i = 0; mask && i < 8; i++) {
- u32 mcc = nv_rd32(priv, 0x640180 + (i * 0x20));
- if (mcc & (1 << head))
- exec_script(priv, head, i, mcc, 1);
- }
-
- nv_wr32(priv, 0x6101d4, 0x00000000);
- nv_wr32(priv, 0x6109d4, 0x00000000);
- nv_wr32(priv, 0x6101d0, 0x80000000);
-}
-
static void
-nvd0_display_unk2_calc_tu(struct nv50_disp_priv *priv, int head, int or)
-{
- const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020));
- const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300));
- const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
- const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
- const u32 hoff = (head * 0x800);
- const u32 soff = ( or * 0x800);
- const u32 loff = (link * 0x080) + soff;
- const u32 symbol = 100000;
- const u32 TU = 64;
- u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x000f0000;
- u32 clksor = nv_rd32(priv, 0x612300 + soff);
- u32 datarate, link_nr, link_bw, bits;
- u64 ratio, value;
-
- if ((conf & 0x3c0) == 0x180) bits = 30;
- else if ((conf & 0x3c0) == 0x140) bits = 24;
- else bits = 18;
- datarate = (pclk * bits) / 8;
-
- if (dpctrl > 0x00030000) link_nr = 4;
- else if (dpctrl > 0x00010000) link_nr = 2;
- else link_nr = 1;
-
- link_bw = (clksor & 0x007c0000) >> 18;
- link_bw *= 27000;
-
- ratio = datarate;
- ratio *= symbol;
- do_div(ratio, link_nr * link_bw);
-
- value = (symbol - ratio) * TU;
- value *= ratio;
- do_div(value, symbol);
- do_div(value, symbol);
-
- value += 5;
- value |= 0x08000000;
-
- nv_wr32(priv, 0x616610 + hoff, value);
-}
-
-static void
-nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
-{
- u32 pclk;
- int i;
-
- for (i = 0; mask && i < 8; i++) {
- u32 mcc = nv_rd32(priv, 0x640180 + (i * 0x20));
- if (mcc & (1 << head))
- exec_script(priv, head, i, mcc, 2);
- }
-
- pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
- nv_debug(priv, "head %d pclk %d mask 0x%08x\n", head, pclk, mask);
- if (pclk && (mask & 0x00010000)) {
- struct nouveau_clock *clk = nouveau_clock(priv);
- clk->pll_set(clk, PLL_VPLL0 + head, pclk);
- }
-
- nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
-
- for (i = 0; mask && i < 8; i++) {
- u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20)), cfg;
- if (mcp & (1 << head)) {
- if ((cfg = exec_clkcmp(priv, head, i, mcp, 0, pclk))) {
- u32 addr, mask, data = 0x00000000;
- if (i < 4) {
- addr = 0x612280 + ((i - 0) * 0x800);
- mask = 0xffffffff;
- } else {
- switch (mcp & 0x00000f00) {
- case 0x00000800:
- case 0x00000900:
- nvd0_display_unk2_calc_tu(priv, head, i - 4);
- break;
- default:
- break;
- }
-
- addr = 0x612300 + ((i - 4) * 0x800);
- mask = 0x00000707;
- if (cfg & 0x00000100)
- data = 0x00000101;
- }
- nv_mask(priv, addr, mask, data);
- }
- break;
- }
- }
-
- nv_wr32(priv, 0x6101d4, 0x00000000);
- nv_wr32(priv, 0x6109d4, 0x00000000);
- nv_wr32(priv, 0x6101d0, 0x80000000);
-}
-
-static void
-nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
-{
- int pclk, i;
-
- pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
-
- for (i = 0; mask && i < 8; i++) {
- u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20));
- if (mcp & (1 << head))
- exec_clkcmp(priv, head, i, mcp, 1, pclk);
- }
-
- nv_wr32(priv, 0x6101d4, 0x00000000);
- nv_wr32(priv, 0x6109d4, 0x00000000);
- nv_wr32(priv, 0x6101d0, 0x80000000);
-}
-
-static void
-nvd0_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
+nvd0_disp_intr_vblank(struct nvd0_disp_priv *priv, int crtc)
{
struct nouveau_bar *bar = nouveau_bar(priv);
struct nouveau_disp *disp = &priv->base;
@@ -851,71 +65,14 @@ nvd0_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
disp->vblank.notify(disp->vblank.data, crtc);
}
-void
+static void
nvd0_disp_intr(struct nouveau_subdev *subdev)
{
- struct nv50_disp_priv *priv = (void *)subdev;
+ struct nvd0_disp_priv *priv = (void *)subdev;
u32 intr = nv_rd32(priv, 0x610088);
int i;
- if (intr & 0x00000001) {
- u32 stat = nv_rd32(priv, 0x61008c);
- nv_wr32(priv, 0x61008c, stat);
- intr &= ~0x00000001;
- }
-
- if (intr & 0x00000002) {
- u32 stat = nv_rd32(priv, 0x61009c);
- int chid = ffs(stat) - 1;
- if (chid >= 0) {
- u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12));
- u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12));
- u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12));
-
- nv_error(priv, "chid %d mthd 0x%04x data 0x%08x "
- "0x%08x 0x%08x\n",
- chid, (mthd & 0x0000ffc), data, mthd, unkn);
- nv_wr32(priv, 0x61009c, (1 << chid));
- nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000);
- }
-
- intr &= ~0x00000002;
- }
-
- if (intr & 0x00100000) {
- u32 stat = nv_rd32(priv, 0x6100ac);
- u32 mask = 0, crtc = ~0;
-
- while (!mask && ++crtc < priv->head.nr)
- mask = nv_rd32(priv, 0x6101d4 + (crtc * 0x800));
-
- if (stat & 0x00000001) {
- nv_wr32(priv, 0x6100ac, 0x00000001);
- nvd0_display_unk1_handler(priv, crtc, mask);
- stat &= ~0x00000001;
- }
-
- if (stat & 0x00000002) {
- nv_wr32(priv, 0x6100ac, 0x00000002);
- nvd0_display_unk2_handler(priv, crtc, mask);
- stat &= ~0x00000002;
- }
-
- if (stat & 0x00000004) {
- nv_wr32(priv, 0x6100ac, 0x00000004);
- nvd0_display_unk4_handler(priv, crtc, mask);
- stat &= ~0x00000004;
- }
-
- if (stat) {
- nv_info(priv, "unknown intr24 0x%08x\n", stat);
- nv_wr32(priv, 0x6100ac, stat);
- }
-
- intr &= ~0x00100000;
- }
-
- for (i = 0; i < priv->head.nr; i++) {
+ for (i = 0; i < 4; i++) {
u32 mask = 0x01000000 << i;
if (mask & intr) {
u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
@@ -929,10 +86,10 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
static int
nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
{
- struct nv50_disp_priv *priv;
+ struct nvd0_disp_priv *priv;
int ret;
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
@@ -941,23 +98,8 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- nv_engine(priv)->sclass = nvd0_disp_base_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_engine(priv)->sclass = nvd0_disp_sclass;
nv_subdev(priv)->intr = nvd0_disp_intr;
- priv->sclass = nvd0_disp_sclass;
- priv->head.nr = nv_rd32(priv, 0x022448);
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hda_eld = nvd0_hda_eld;
- priv->sor.hdmi = nvd0_hdmi_ctrl;
- priv->sor.dp_train = nvd0_sor_dp_train;
- priv->sor.dp_train_init = nv94_sor_dp_train_init;
- priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
- priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl;
- priv->sor.dp_drvctl = nvd0_sor_dp_drvctl;
INIT_LIST_HEAD(&priv->base.vblank.list);
spin_lock_init(&priv->base.vblank.lock);
@@ -966,7 +108,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass
nvd0_disp_oclass = {
- .handle = NV_ENGINE(DISP, 0x90),
+ .handle = NV_ENGINE(DISP, 0xd0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvd0_disp_ctor,
.dtor = _nouveau_disp_dtor,
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
deleted file mode 100644
index 259537c4587e..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include
-
-#include "nv50.h"
-
-static struct nouveau_oclass
-nve0_disp_sclass[] = {
- { NVE0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs },
- { NVE0_DISP_SYNC_CLASS, &nvd0_disp_sync_ofuncs },
- { NVE0_DISP_OVLY_CLASS, &nvd0_disp_ovly_ofuncs },
- { NVE0_DISP_OIMM_CLASS, &nvd0_disp_oimm_ofuncs },
- { NVE0_DISP_CURS_CLASS, &nvd0_disp_curs_ofuncs },
- {}
-};
-
-static struct nouveau_oclass
-nve0_disp_base_oclass[] = {
- { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
- {}
-};
-
-static int
-nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nve0_disp_base_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nvd0_disp_intr;
- priv->sclass = nve0_disp_sclass;
- priv->head.nr = nv_rd32(priv, 0x022448);
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hda_eld = nvd0_hda_eld;
- priv->sor.hdmi = nvd0_hdmi_ctrl;
- priv->sor.dp_train = nvd0_sor_dp_train;
- priv->sor.dp_train_init = nv94_sor_dp_train_init;
- priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
- priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl;
- priv->sor.dp_drvctl = nvd0_sor_dp_drvctl;
-
- INIT_LIST_HEAD(&priv->base.vblank.list);
- spin_lock_init(&priv->base.vblank.lock);
- return 0;
-}
-
-struct nouveau_oclass
-nve0_disp_oclass = {
- .handle = NV_ENGINE(DISP, 0x91),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
deleted file mode 100644
index 39b6b67732d0..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include
-#include
-#include
-
-#include "nv50.h"
-
-int
-nv50_sor_power(struct nv50_disp_priv *priv, int or, u32 data)
-{
- const u32 stat = data & NV50_DISP_SOR_PWR_STATE;
- const u32 soff = (or * 0x800);
- nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
- nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat);
- nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
- nv_wait(priv, 0x61c030 + soff, 0x10000000, 0x00000000);
- return 0;
-}
-
-int
-nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nouveau_bios *bios = nouveau_bios(priv);
- const u16 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
- const u8 head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
- const u8 link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
- const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR);
- const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
- struct dcb_output outp;
- u8 ver, hdr;
- u32 data;
- int ret = -EINVAL;
-
- if (size < sizeof(u32))
- return -EINVAL;
- data = *(u32 *)args;
-
- if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
- return -ENODEV;
-
- switch (mthd & ~0x3f) {
- case NV50_DISP_SOR_PWR:
- ret = priv->sor.power(priv, or, data);
- break;
- case NVA3_DISP_SOR_HDA_ELD:
- ret = priv->sor.hda_eld(priv, or, args, size);
- break;
- case NV84_DISP_SOR_HDMI_PWR:
- ret = priv->sor.hdmi(priv, head, or, data);
- break;
- case NV50_DISP_SOR_LVDS_SCRIPT:
- priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID;
- ret = 0;
- break;
- case NV94_DISP_SOR_DP_TRAIN:
- switch (data & NV94_DISP_SOR_DP_TRAIN_OP) {
- case NV94_DISP_SOR_DP_TRAIN_OP_PATTERN:
- ret = priv->sor.dp_train(priv, or, link, type, mask, data, &outp);
- break;
- case NV94_DISP_SOR_DP_TRAIN_OP_INIT:
- ret = priv->sor.dp_train_init(priv, or, link, head, type, mask, data, &outp);
- break;
- case NV94_DISP_SOR_DP_TRAIN_OP_FINI:
- ret = priv->sor.dp_train_fini(priv, or, link, head, type, mask, data, &outp);
- break;
- default:
- break;
- }
- break;
- case NV94_DISP_SOR_DP_LNKCTL:
- ret = priv->sor.dp_lnkctl(priv, or, link, head, type, mask, data, &outp);
- break;
- case NV94_DISP_SOR_DP_DRVCTL(0):
- case NV94_DISP_SOR_DP_DRVCTL(1):
- case NV94_DISP_SOR_DP_DRVCTL(2):
- case NV94_DISP_SOR_DP_DRVCTL(3):
- ret = priv->sor.dp_drvctl(priv, or, link, (mthd & 0xc0) >> 6,
- type, mask, data, &outp);
- break;
- default:
- BUG_ON(1);
- }
-
- return ret;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c
deleted file mode 100644
index f6edd009762e..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include
-#include
-#include
-#include
-
-#include "nv50.h"
-
-static inline u32
-nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
-{
- static const u8 nvaf[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
- static const u8 nv94[] = { 16, 8, 0, 24 };
- if (nv_device(priv)->chipset == 0xaf)
- return nvaf[lane];
- return nv94[lane];
-}
-
-int
-nv94_sor_dp_train_init(struct nv50_disp_priv *priv, int or, int link, int head,
- u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_dpout info;
- u8 ver, hdr, cnt, len;
- u16 outp;
-
- outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info);
- if (outp) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .outp = dcbo,
- .crtc = head,
- .execute = 1,
- };
-
- if (data & NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_ON)
- init.offset = info.script[2];
- else
- init.offset = info.script[3];
- nvbios_exec(&init);
-
- init.offset = info.script[0];
- nvbios_exec(&init);
- }
-
- return 0;
-}
-
-int
-nv94_sor_dp_train_fini(struct nv50_disp_priv *priv, int or, int link, int head,
- u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_dpout info;
- u8 ver, hdr, cnt, len;
- u16 outp;
-
- outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info);
- if (outp) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = info.script[1],
- .outp = dcbo,
- .crtc = head,
- .execute = 1,
- };
-
- nvbios_exec(&init);
- }
-
- return 0;
-}
-
-int
-nv94_sor_dp_train(struct nv50_disp_priv *priv, int or, int link,
- u16 type, u16 mask, u32 data, struct dcb_output *info)
-{
- const u32 loff = (or * 0x800) + (link * 0x80);
- const u32 patt = (data & NV94_DISP_SOR_DP_TRAIN_PATTERN);
- nv_mask(priv, 0x61c10c + loff, 0x0f000000, patt << 24);
- return 0;
-}
-
-int
-nv94_sor_dp_lnkctl(struct nv50_disp_priv *priv, int or, int link, int head,
- u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- const u32 loff = (or * 0x800) + (link * 0x80);
- const u32 soff = (or * 0x800);
- u16 link_bw = (data & NV94_DISP_SOR_DP_LNKCTL_WIDTH) >> 8;
- u8 link_nr = (data & NV94_DISP_SOR_DP_LNKCTL_COUNT);
- u32 dpctrl = 0x00000000;
- u32 clksor = 0x00000000;
- u32 outp, lane = 0;
- u8 ver, hdr, cnt, len;
- struct nvbios_dpout info;
- int i;
-
- /* -> 10Khz units */
- link_bw *= 2700;
-
- outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info);
- if (outp && info.lnkcmp) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = 0x0000,
- .outp = dcbo,
- .crtc = head,
- .execute = 1,
- };
-
- while (link_bw < nv_ro16(bios, info.lnkcmp))
- info.lnkcmp += 4;
- init.offset = nv_ro16(bios, info.lnkcmp + 2);
-
- nvbios_exec(&init);
- }
-
- dpctrl |= ((1 << link_nr) - 1) << 16;
- if (data & NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH)
- dpctrl |= 0x00004000;
- if (link_bw > 16200)
- clksor |= 0x00040000;
-
- for (i = 0; i < link_nr; i++)
- lane |= 1 << (nv94_sor_dp_lane_map(priv, i) >> 3);
-
- nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor);
- nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
- nv_mask(priv, 0x61c130 + loff, 0x0000000f, lane);
- return 0;
-}
-
-int
-nv94_sor_dp_drvctl(struct nv50_disp_priv *priv, int or, int link, int lane,
- u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- const u32 loff = (or * 0x800) + (link * 0x80);
- const u8 swing = (data & NV94_DISP_SOR_DP_DRVCTL_VS) >> 8;
- const u8 preem = (data & NV94_DISP_SOR_DP_DRVCTL_PE);
- u32 addr, shift = nv94_sor_dp_lane_map(priv, lane);
- u8 ver, hdr, cnt, len;
- struct nvbios_dpout outp;
- struct nvbios_dpcfg ocfg;
-
- addr = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &outp);
- if (!addr)
- return -ENODEV;
-
- addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, &ver, &hdr, &cnt, &len, &ocfg);
- if (!addr)
- return -EINVAL;
-
- nv_mask(priv, 0x61c118 + loff, 0x000000ff << shift, ocfg.drv << shift);
- nv_mask(priv, 0x61c120 + loff, 0x000000ff << shift, ocfg.pre << shift);
- nv_mask(priv, 0x61c130 + loff, 0x0000ff00, ocfg.unk << 8);
- return 0;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
deleted file mode 100644
index c37ce7e29f5d..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2012 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
-
-#include
-#include
-#include
-#include
-
-#include "nv50.h"
-
-static inline u32
-nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
-{
- static const u8 nvd0[] = { 16, 8, 0, 24 };
- return nvd0[lane];
-}
-
-int
-nvd0_sor_dp_train(struct nv50_disp_priv *priv, int or, int link,
- u16 type, u16 mask, u32 data, struct dcb_output *info)
-{
- const u32 loff = (or * 0x800) + (link * 0x80);
- const u32 patt = (data & NV94_DISP_SOR_DP_TRAIN_PATTERN);
- nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * patt);
- return 0;
-}
-
-int
-nvd0_sor_dp_lnkctl(struct nv50_disp_priv *priv, int or, int link, int head,
- u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- const u32 loff = (or * 0x800) + (link * 0x80);
- const u32 soff = (or * 0x800);
- const u8 link_bw = (data & NV94_DISP_SOR_DP_LNKCTL_WIDTH) >> 8;
- const u8 link_nr = (data & NV94_DISP_SOR_DP_LNKCTL_COUNT);
- u32 dpctrl = 0x00000000;
- u32 clksor = 0x00000000;
- u32 outp, lane = 0;
- u8 ver, hdr, cnt, len;
- struct nvbios_dpout info;
- int i;
-
- outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info);
- if (outp && info.lnkcmp) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = 0x0000,
- .outp = dcbo,
- .crtc = head,
- .execute = 1,
- };
-
- while (nv_ro08(bios, info.lnkcmp) < link_bw)
- info.lnkcmp += 3;
- init.offset = nv_ro16(bios, info.lnkcmp + 1);
-
- nvbios_exec(&init);
- }
-
- clksor |= link_bw << 18;
- dpctrl |= ((1 << link_nr) - 1) << 16;
- if (data & NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH)
- dpctrl |= 0x00004000;
-
- for (i = 0; i < link_nr; i++)
- lane |= 1 << (nvd0_sor_dp_lane_map(priv, i) >> 3);
-
- nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor);
- nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
- nv_mask(priv, 0x61c130 + loff, 0x0000000f, lane);
- return 0;
-}
-
-int
-nvd0_sor_dp_drvctl(struct nv50_disp_priv *priv, int or, int link, int lane,
- u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- const u32 loff = (or * 0x800) + (link * 0x80);
- const u8 swing = (data & NV94_DISP_SOR_DP_DRVCTL_VS) >> 8;
- const u8 preem = (data & NV94_DISP_SOR_DP_DRVCTL_PE);
- u32 addr, shift = nvd0_sor_dp_lane_map(priv, lane);
- u8 ver, hdr, cnt, len;
- struct nvbios_dpout outp;
- struct nvbios_dpcfg ocfg;
-
- addr = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &outp);
- if (!addr)
- return -ENODEV;
-
- addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, &ver, &hdr, &cnt, &len, &ocfg);
- if (!addr)
- return -EINVAL;
-
- nv_mask(priv, 0x61c118 + loff, 0x000000ff << shift, ocfg.drv << shift);
- nv_mask(priv, 0x61c120 + loff, 0x000000ff << shift, ocfg.pre << shift);
- nv_mask(priv, 0x61c130 + loff, 0x0000ff00, ocfg.unk << 8);
- nv_mask(priv, 0x61c13c + loff, 0x00000000, 0x00000000);
- return 0;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c b/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c
index 5103e88d1877..e1f013d39768 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c
@@ -28,39 +28,37 @@
#include
#include
-static int
-nouveau_dmaobj_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
+int
+nouveau_dmaobj_create_(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass,
+ void *data, u32 size, int len, void **pobject)
{
- struct nouveau_dmaeng *dmaeng = (void *)engine;
- struct nouveau_dmaobj *dmaobj;
- struct nouveau_gpuobj *gpuobj;
struct nv_dma_class *args = data;
+ struct nouveau_dmaobj *object;
int ret;
if (size < sizeof(*args))
return -EINVAL;
- ret = nouveau_object_create(parent, engine, oclass, 0, &dmaobj);
- *pobject = nv_object(dmaobj);
+ ret = nouveau_object_create_(parent, engine, oclass, 0, len, pobject);
+ object = *pobject;
if (ret)
return ret;
switch (args->flags & NV_DMA_TARGET_MASK) {
case NV_DMA_TARGET_VM:
- dmaobj->target = NV_MEM_TARGET_VM;
+ object->target = NV_MEM_TARGET_VM;
break;
case NV_DMA_TARGET_VRAM:
- dmaobj->target = NV_MEM_TARGET_VRAM;
+ object->target = NV_MEM_TARGET_VRAM;
break;
case NV_DMA_TARGET_PCI:
- dmaobj->target = NV_MEM_TARGET_PCI;
+ object->target = NV_MEM_TARGET_PCI;
break;
case NV_DMA_TARGET_PCI_US:
case NV_DMA_TARGET_AGP:
- dmaobj->target = NV_MEM_TARGET_PCI_NOSNOOP;
+ object->target = NV_MEM_TARGET_PCI_NOSNOOP;
break;
default:
return -EINVAL;
@@ -68,53 +66,22 @@ nouveau_dmaobj_ctor(struct nouveau_object *parent,
switch (args->flags & NV_DMA_ACCESS_MASK) {
case NV_DMA_ACCESS_VM:
- dmaobj->access = NV_MEM_ACCESS_VM;
+ object->access = NV_MEM_ACCESS_VM;
break;
case NV_DMA_ACCESS_RD:
- dmaobj->access = NV_MEM_ACCESS_RO;
+ object->access = NV_MEM_ACCESS_RO;
break;
case NV_DMA_ACCESS_WR:
- dmaobj->access = NV_MEM_ACCESS_WO;
+ object->access = NV_MEM_ACCESS_WO;
break;
case NV_DMA_ACCESS_RDWR:
- dmaobj->access = NV_MEM_ACCESS_RW;
+ object->access = NV_MEM_ACCESS_RW;
break;
default:
return -EINVAL;
}
- dmaobj->start = args->start;
- dmaobj->limit = args->limit;
- dmaobj->conf0 = args->conf0;
-
- switch (nv_mclass(parent)) {
- case NV_DEVICE_CLASS:
- /* delayed, or no, binding */
- break;
- default:
- ret = dmaeng->bind(dmaeng, *pobject, dmaobj, &gpuobj);
- if (ret == 0) {
- nouveau_object_ref(NULL, pobject);
- *pobject = nv_object(gpuobj);
- }
- break;
- }
-
- return ret;
+ object->start = args->start;
+ object->limit = args->limit;
+ return 0;
}
-
-static struct nouveau_ofuncs
-nouveau_dmaobj_ofuncs = {
- .ctor = nouveau_dmaobj_ctor,
- .dtor = nouveau_object_destroy,
- .init = nouveau_object_init,
- .fini = nouveau_object_fini,
-};
-
-struct nouveau_oclass
-nouveau_dmaobj_sclass[] = {
- { NV_DMA_FROM_MEMORY_CLASS, &nouveau_dmaobj_ofuncs },
- { NV_DMA_TO_MEMORY_CLASS, &nouveau_dmaobj_ofuncs },
- { NV_DMA_IN_MEMORY_CLASS, &nouveau_dmaobj_ofuncs },
- {}
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c b/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c
index 027d8217c0fa..9f4cc2f31994 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c
@@ -34,6 +34,10 @@ struct nv04_dmaeng_priv {
struct nouveau_dmaeng base;
};
+struct nv04_dmaobj_priv {
+ struct nouveau_dmaobj base;
+};
+
static int
nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
struct nouveau_object *parent,
@@ -49,18 +53,6 @@ nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
u32 length = dmaobj->limit - dmaobj->start;
int ret;
- if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
- switch (nv_mclass(parent->parent)) {
- case NV03_CHANNEL_DMA_CLASS:
- case NV10_CHANNEL_DMA_CLASS:
- case NV17_CHANNEL_DMA_CLASS:
- case NV40_CHANNEL_DMA_CLASS:
- break;
- default:
- return -EINVAL;
- }
- }
-
if (dmaobj->target == NV_MEM_TARGET_VM) {
if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass) {
struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0];
@@ -113,6 +105,56 @@ nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
return ret;
}
+static int
+nv04_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_dmaeng *dmaeng = (void *)engine;
+ struct nv04_dmaobj_priv *dmaobj;
+ struct nouveau_gpuobj *gpuobj;
+ int ret;
+
+ ret = nouveau_dmaobj_create(parent, engine, oclass,
+ data, size, &dmaobj);
+ *pobject = nv_object(dmaobj);
+ if (ret)
+ return ret;
+
+ switch (nv_mclass(parent)) {
+ case NV_DEVICE_CLASS:
+ break;
+ case NV03_CHANNEL_DMA_CLASS:
+ case NV10_CHANNEL_DMA_CLASS:
+ case NV17_CHANNEL_DMA_CLASS:
+ case NV40_CHANNEL_DMA_CLASS:
+ ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj);
+ nouveau_object_ref(NULL, pobject);
+ *pobject = nv_object(gpuobj);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct nouveau_ofuncs
+nv04_dmaobj_ofuncs = {
+ .ctor = nv04_dmaobj_ctor,
+ .dtor = _nouveau_dmaobj_dtor,
+ .init = _nouveau_dmaobj_init,
+ .fini = _nouveau_dmaobj_fini,
+};
+
+static struct nouveau_oclass
+nv04_dmaobj_sclass[] = {
+ { 0x0002, &nv04_dmaobj_ofuncs },
+ { 0x0003, &nv04_dmaobj_ofuncs },
+ { 0x003d, &nv04_dmaobj_ofuncs },
+ {}
+};
+
static int
nv04_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@@ -126,7 +168,7 @@ nv04_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- nv_engine(priv)->sclass = nouveau_dmaobj_sclass;
+ priv->base.base.sclass = nv04_dmaobj_sclass;
priv->base.bind = nv04_dmaobj_bind;
return 0;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c
index 750183f7c057..045d2565e289 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c
@@ -32,74 +32,36 @@ struct nv50_dmaeng_priv {
struct nouveau_dmaeng base;
};
+struct nv50_dmaobj_priv {
+ struct nouveau_dmaobj base;
+};
+
static int
nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **pgpuobj)
{
- u32 flags0 = nv_mclass(dmaobj);
- u32 flags5 = 0x00000000;
+ u32 flags = nv_mclass(dmaobj);
int ret;
- if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
- switch (nv_mclass(parent->parent)) {
- case NV50_CHANNEL_DMA_CLASS:
- case NV84_CHANNEL_DMA_CLASS:
- case NV50_CHANNEL_IND_CLASS:
- case NV84_CHANNEL_IND_CLASS:
- case NV50_DISP_MAST_CLASS:
- case NV84_DISP_MAST_CLASS:
- case NV94_DISP_MAST_CLASS:
- case NVA0_DISP_MAST_CLASS:
- case NVA3_DISP_MAST_CLASS:
- case NV50_DISP_SYNC_CLASS:
- case NV84_DISP_SYNC_CLASS:
- case NV94_DISP_SYNC_CLASS:
- case NVA0_DISP_SYNC_CLASS:
- case NVA3_DISP_SYNC_CLASS:
- case NV50_DISP_OVLY_CLASS:
- case NV84_DISP_OVLY_CLASS:
- case NV94_DISP_OVLY_CLASS:
- case NVA0_DISP_OVLY_CLASS:
- case NVA3_DISP_OVLY_CLASS:
- break;
- default:
- return -EINVAL;
- }
- }
-
- if (!(dmaobj->conf0 & NV50_DMA_CONF0_ENABLE)) {
- if (dmaobj->target == NV_MEM_TARGET_VM) {
- dmaobj->conf0 = NV50_DMA_CONF0_PRIV_VM;
- dmaobj->conf0 |= NV50_DMA_CONF0_PART_VM;
- dmaobj->conf0 |= NV50_DMA_CONF0_COMP_VM;
- dmaobj->conf0 |= NV50_DMA_CONF0_TYPE_VM;
- } else {
- dmaobj->conf0 = NV50_DMA_CONF0_PRIV_US;
- dmaobj->conf0 |= NV50_DMA_CONF0_PART_256;
- dmaobj->conf0 |= NV50_DMA_CONF0_COMP_NONE;
- dmaobj->conf0 |= NV50_DMA_CONF0_TYPE_LINEAR;
- }
- }
-
- flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_COMP) << 22;
- flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_TYPE) << 22;
- flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_PRIV);
- flags5 |= (dmaobj->conf0 & NV50_DMA_CONF0_PART);
-
switch (dmaobj->target) {
case NV_MEM_TARGET_VM:
- flags0 |= 0x00000000;
+ flags |= 0x00000000;
+ flags |= 0x60000000; /* COMPRESSION_USEVM */
+ flags |= 0x1fc00000; /* STORAGE_TYPE_USEVM */
break;
case NV_MEM_TARGET_VRAM:
- flags0 |= 0x00010000;
+ flags |= 0x00010000;
+ flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
break;
case NV_MEM_TARGET_PCI:
- flags0 |= 0x00020000;
+ flags |= 0x00020000;
+ flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
break;
case NV_MEM_TARGET_PCI_NOSNOOP:
- flags0 |= 0x00030000;
+ flags |= 0x00030000;
+ flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
break;
default:
return -EINVAL;
@@ -109,28 +71,78 @@ nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
case NV_MEM_ACCESS_VM:
break;
case NV_MEM_ACCESS_RO:
- flags0 |= 0x00040000;
+ flags |= 0x00040000;
break;
case NV_MEM_ACCESS_WO:
case NV_MEM_ACCESS_RW:
- flags0 |= 0x00080000;
+ flags |= 0x00080000;
break;
}
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (ret == 0) {
- nv_wo32(*pgpuobj, 0x00, flags0);
+ nv_wo32(*pgpuobj, 0x00, flags);
nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->limit));
nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->start));
nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->limit) << 24 |
upper_32_bits(dmaobj->start));
nv_wo32(*pgpuobj, 0x10, 0x00000000);
- nv_wo32(*pgpuobj, 0x14, flags5);
+ nv_wo32(*pgpuobj, 0x14, 0x00000000);
}
return ret;
}
+static int
+nv50_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_dmaeng *dmaeng = (void *)engine;
+ struct nv50_dmaobj_priv *dmaobj;
+ struct nouveau_gpuobj *gpuobj;
+ int ret;
+
+ ret = nouveau_dmaobj_create(parent, engine, oclass,
+ data, size, &dmaobj);
+ *pobject = nv_object(dmaobj);
+ if (ret)
+ return ret;
+
+ switch (nv_mclass(parent)) {
+ case NV_DEVICE_CLASS:
+ break;
+ case NV50_CHANNEL_DMA_CLASS:
+ case NV84_CHANNEL_DMA_CLASS:
+ case NV50_CHANNEL_IND_CLASS:
+ case NV84_CHANNEL_IND_CLASS:
+ ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj);
+ nouveau_object_ref(NULL, pobject);
+ *pobject = nv_object(gpuobj);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct nouveau_ofuncs
+nv50_dmaobj_ofuncs = {
+ .ctor = nv50_dmaobj_ctor,
+ .dtor = _nouveau_dmaobj_dtor,
+ .init = _nouveau_dmaobj_init,
+ .fini = _nouveau_dmaobj_fini,
+};
+
+static struct nouveau_oclass
+nv50_dmaobj_sclass[] = {
+ { 0x0002, &nv50_dmaobj_ofuncs },
+ { 0x0003, &nv50_dmaobj_ofuncs },
+ { 0x003d, &nv50_dmaobj_ofuncs },
+ {}
+};
+
static int
nv50_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@@ -144,7 +156,7 @@ nv50_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- nv_engine(priv)->sclass = nouveau_dmaobj_sclass;
+ priv->base.base.sclass = nv50_dmaobj_sclass;
priv->base.bind = nv50_dmaobj_bind;
return 0;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c
index cd3970d03b80..5baa08695535 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c
@@ -22,9 +22,7 @@
* Authors: Ben Skeggs
*/
-#include
#include
-#include
#include
#include
@@ -33,85 +31,44 @@ struct nvc0_dmaeng_priv {
struct nouveau_dmaeng base;
};
+struct nvc0_dmaobj_priv {
+ struct nouveau_dmaobj base;
+};
+
static int
-nvc0_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
- struct nouveau_object *parent,
- struct nouveau_dmaobj *dmaobj,
- struct nouveau_gpuobj **pgpuobj)
+nvc0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
{
- u32 flags0 = nv_mclass(dmaobj);
- u32 flags5 = 0x00000000;
+ struct nvc0_dmaobj_priv *dmaobj;
int ret;
- if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
- switch (nv_mclass(parent->parent)) {
- case NVA3_DISP_MAST_CLASS:
- case NVA3_DISP_SYNC_CLASS:
- case NVA3_DISP_OVLY_CLASS:
- break;
- default:
- return -EINVAL;
- }
- } else
- return 0;
-
- if (!(dmaobj->conf0 & NVC0_DMA_CONF0_ENABLE)) {
- if (dmaobj->target == NV_MEM_TARGET_VM) {
- dmaobj->conf0 = NVC0_DMA_CONF0_PRIV_VM;
- dmaobj->conf0 |= NVC0_DMA_CONF0_TYPE_VM;
- } else {
- dmaobj->conf0 = NVC0_DMA_CONF0_PRIV_US;
- dmaobj->conf0 |= NVC0_DMA_CONF0_TYPE_LINEAR;
- dmaobj->conf0 |= 0x00020000;
- }
- }
-
- flags0 |= (dmaobj->conf0 & NVC0_DMA_CONF0_TYPE) << 22;
- flags0 |= (dmaobj->conf0 & NVC0_DMA_CONF0_PRIV);
- flags5 |= (dmaobj->conf0 & NVC0_DMA_CONF0_UNKN);
+ ret = nouveau_dmaobj_create(parent, engine, oclass, data, size, &dmaobj);
+ *pobject = nv_object(dmaobj);
+ if (ret)
+ return ret;
- switch (dmaobj->target) {
- case NV_MEM_TARGET_VM:
- flags0 |= 0x00000000;
- break;
- case NV_MEM_TARGET_VRAM:
- flags0 |= 0x00010000;
- break;
- case NV_MEM_TARGET_PCI:
- flags0 |= 0x00020000;
- break;
- case NV_MEM_TARGET_PCI_NOSNOOP:
- flags0 |= 0x00030000;
- break;
- default:
+ if (dmaobj->base.target != NV_MEM_TARGET_VM || dmaobj->base.start)
return -EINVAL;
- }
- switch (dmaobj->access) {
- case NV_MEM_ACCESS_VM:
- break;
- case NV_MEM_ACCESS_RO:
- flags0 |= 0x00040000;
- break;
- case NV_MEM_ACCESS_WO:
- case NV_MEM_ACCESS_RW:
- flags0 |= 0x00080000;
- break;
- }
+ return 0;
+}
- ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
- if (ret == 0) {
- nv_wo32(*pgpuobj, 0x00, flags0);
- nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->limit));
- nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->start));
- nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->limit) << 24 |
- upper_32_bits(dmaobj->start));
- nv_wo32(*pgpuobj, 0x10, 0x00000000);
- nv_wo32(*pgpuobj, 0x14, flags5);
- }
+static struct nouveau_ofuncs
+nvc0_dmaobj_ofuncs = {
+ .ctor = nvc0_dmaobj_ctor,
+ .dtor = _nouveau_dmaobj_dtor,
+ .init = _nouveau_dmaobj_init,
+ .fini = _nouveau_dmaobj_fini,
+};
- return ret;
-}
+static struct nouveau_oclass
+nvc0_dmaobj_sclass[] = {
+ { 0x0002, &nvc0_dmaobj_ofuncs },
+ { 0x0003, &nvc0_dmaobj_ofuncs },
+ { 0x003d, &nvc0_dmaobj_ofuncs },
+ {}
+};
static int
nvc0_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
@@ -126,8 +83,7 @@ nvc0_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- nv_engine(priv)->sclass = nouveau_dmaobj_sclass;
- priv->base.bind = nvc0_dmaobj_bind;
+ priv->base.base.sclass = nvc0_dmaobj_sclass;
return 0;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c
deleted file mode 100644
index d1528752980c..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012 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
-#include
-
-#include
-#include
-
-struct nvd0_dmaeng_priv {
- struct nouveau_dmaeng base;
-};
-
-static int
-nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
- struct nouveau_object *parent,
- struct nouveau_dmaobj *dmaobj,
- struct nouveau_gpuobj **pgpuobj)
-{
- u32 flags0 = 0x00000000;
- int ret;
-
- if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
- switch (nv_mclass(parent->parent)) {
- case NVD0_DISP_MAST_CLASS:
- case NVD0_DISP_SYNC_CLASS:
- case NVD0_DISP_OVLY_CLASS:
- case NVE0_DISP_MAST_CLASS:
- case NVE0_DISP_SYNC_CLASS:
- case NVE0_DISP_OVLY_CLASS:
- break;
- default:
- return -EINVAL;
- }
- } else
- return 0;
-
- if (!(dmaobj->conf0 & NVD0_DMA_CONF0_ENABLE)) {
- if (dmaobj->target == NV_MEM_TARGET_VM) {
- dmaobj->conf0 |= NVD0_DMA_CONF0_TYPE_VM;
- dmaobj->conf0 |= NVD0_DMA_CONF0_PAGE_LP;
- } else {
- dmaobj->conf0 |= NVD0_DMA_CONF0_TYPE_LINEAR;
- dmaobj->conf0 |= NVD0_DMA_CONF0_PAGE_SP;
- }
- }
-
- flags0 |= (dmaobj->conf0 & NVD0_DMA_CONF0_TYPE) << 20;
- flags0 |= (dmaobj->conf0 & NVD0_DMA_CONF0_PAGE) >> 4;
-
- switch (dmaobj->target) {
- case NV_MEM_TARGET_VRAM:
- flags0 |= 0x00000009;
- break;
- default:
- return -EINVAL;
- break;
- }
-
- ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
- if (ret == 0) {
- nv_wo32(*pgpuobj, 0x00, flags0);
- nv_wo32(*pgpuobj, 0x04, dmaobj->start >> 8);
- nv_wo32(*pgpuobj, 0x08, dmaobj->limit >> 8);
- nv_wo32(*pgpuobj, 0x0c, 0x00000000);
- nv_wo32(*pgpuobj, 0x10, 0x00000000);
- nv_wo32(*pgpuobj, 0x14, 0x00000000);
- }
-
- return ret;
-}
-
-static int
-nvd0_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvd0_dmaeng_priv *priv;
- int ret;
-
- ret = nouveau_dmaeng_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nouveau_dmaobj_sclass;
- priv->base.bind = nvd0_dmaobj_bind;
- return 0;
-}
-
-struct nouveau_oclass
-nvd0_dmaeng_oclass = {
- .handle = NV_ENGINE(DMAOBJ, 0xd0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvd0_dmaeng_ctor,
- .dtor = _nouveau_dmaeng_dtor,
- .init = _nouveau_dmaeng_init,
- .fini = _nouveau_dmaeng_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
index c2b9db335816..bbb43c67c2ae 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
@@ -24,7 +24,6 @@
#include
#include
-#include
#include
#include
@@ -34,7 +33,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
int bar, u32 addr, u32 size, u32 pushbuf,
- u64 engmask, int len, void **ptr)
+ u32 engmask, int len, void **ptr)
{
struct nouveau_device *device = nv_device(engine);
struct nouveau_fifo *priv = (void *)engine;
@@ -57,16 +56,18 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
dmaeng = (void *)chan->pushdma->base.engine;
switch (chan->pushdma->base.oclass->handle) {
- case NV_DMA_FROM_MEMORY_CLASS:
- case NV_DMA_IN_MEMORY_CLASS:
+ case 0x0002:
+ case 0x003d:
break;
default:
return -EINVAL;
}
- ret = dmaeng->bind(dmaeng, parent, chan->pushdma, &chan->pushgpu);
- if (ret)
- return ret;
+ if (dmaeng->bind) {
+ ret = dmaeng->bind(dmaeng, parent, chan->pushdma, &chan->pushgpu);
+ if (ret)
+ return ret;
+ }
/* find a free fifo channel */
spin_lock_irqsave(&priv->lock, flags);
@@ -118,14 +119,14 @@ _nouveau_fifo_channel_dtor(struct nouveau_object *object)
}
u32
-_nouveau_fifo_channel_rd32(struct nouveau_object *object, u64 addr)
+_nouveau_fifo_channel_rd32(struct nouveau_object *object, u32 addr)
{
struct nouveau_fifo_chan *chan = (void *)object;
return ioread32_native(chan->user + addr);
}
void
-_nouveau_fifo_channel_wr32(struct nouveau_object *object, u64 addr, u32 data)
+_nouveau_fifo_channel_wr32(struct nouveau_object *object, u32 addr, u32 data)
{
struct nouveau_fifo_chan *chan = (void *)object;
iowrite32_native(data, chan->user + addr);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
index a47a8548f9e0..ea76e3e8c9c2 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
@@ -126,9 +126,9 @@ nv04_fifo_chan_ctor(struct nouveau_object *parent,
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
0x10000, args->pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR), &chan);
+ (1 << NVDEV_ENGINE_DMAOBJ) |
+ (1 << NVDEV_ENGINE_SW) |
+ (1 << NVDEV_ENGINE_GR), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
@@ -440,7 +440,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
}
if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
- nv_error(priv, "CACHE_ERROR - Ch %d/%d "
+ nv_info(priv, "CACHE_ERROR - Ch %d/%d "
"Mthd 0x%04x Data 0x%08x\n",
chid, (mthd >> 13) & 7, mthd & 0x1ffc,
data);
@@ -476,7 +476,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
u32 ib_get = nv_rd32(priv, 0x003334);
u32 ib_put = nv_rd32(priv, 0x003330);
- nv_error(priv, "DMA_PUSHER - Ch %d Get 0x%02x%08x "
+ nv_info(priv, "DMA_PUSHER - Ch %d Get 0x%02x%08x "
"Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
"State 0x%08x (err: %s) Push 0x%08x\n",
chid, ho_get, dma_get, ho_put,
@@ -494,7 +494,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
nv_wr32(priv, 0x003334, ib_put);
}
} else {
- nv_error(priv, "DMA_PUSHER - Ch %d Get 0x%08x "
+ nv_info(priv, "DMA_PUSHER - Ch %d Get 0x%08x "
"Put 0x%08x State 0x%08x (err: %s) Push 0x%08x\n",
chid, dma_get, dma_put, state,
nv_dma_state_err(state), push);
@@ -525,13 +525,14 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
if (device->card_type == NV_50) {
if (status & 0x00000010) {
+ nv50_fb_trap(nouveau_fb(priv), 1);
status &= ~0x00000010;
nv_wr32(priv, 0x002100, 0x00000010);
}
}
if (status) {
- nv_warn(priv, "unknown intr 0x%08x, ch %d\n",
+ nv_info(priv, "unknown intr 0x%08x, ch %d\n",
status, chid);
nv_wr32(priv, NV03_PFIFO_INTR_0, status);
status = 0;
@@ -541,7 +542,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
}
if (status) {
- nv_error(priv, "still angry after %d spins, halt\n", cnt);
+ nv_info(priv, "still angry after %d spins, halt\n", cnt);
nv_wr32(priv, 0x002140, 0);
nv_wr32(priv, 0x000140, 0);
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
index 2c927c1d173b..4ba75422b89d 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
@@ -69,9 +69,9 @@ nv10_fifo_chan_ctor(struct nouveau_object *parent,
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
0x10000, args->pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR), &chan);
+ (1 << NVDEV_ENGINE_DMAOBJ) |
+ (1 << NVDEV_ENGINE_SW) |
+ (1 << NVDEV_ENGINE_GR), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
index a9cb51d38c57..b96e6b0ae2b1 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
@@ -74,10 +74,10 @@ nv17_fifo_chan_ctor(struct nouveau_object *parent,
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
0x10000, args->pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG), /* NV31- */
+ (1 << NVDEV_ENGINE_DMAOBJ) |
+ (1 << NVDEV_ENGINE_SW) |
+ (1 << NVDEV_ENGINE_GR) |
+ (1 << NVDEV_ENGINE_MPEG), /* NV31- */
&chan);
*pobject = nv_object(chan);
if (ret)
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
index 2b1f91721225..559c3b4e1b86 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
@@ -192,10 +192,10 @@ nv40_fifo_chan_ctor(struct nouveau_object *parent,
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x1000, args->pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG), &chan);
+ (1 << NVDEV_ENGINE_DMAOBJ) |
+ (1 << NVDEV_ENGINE_SW) |
+ (1 << NVDEV_ENGINE_GR) |
+ (1 << NVDEV_ENGINE_MPEG), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
index bd096364f680..536e7634a00d 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
@@ -112,6 +112,14 @@ nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend,
return -EINVAL;
}
+ nv_wo32(base->eng, addr + 0x00, 0x00000000);
+ nv_wo32(base->eng, addr + 0x04, 0x00000000);
+ nv_wo32(base->eng, addr + 0x08, 0x00000000);
+ nv_wo32(base->eng, addr + 0x0c, 0x00000000);
+ nv_wo32(base->eng, addr + 0x10, 0x00000000);
+ nv_wo32(base->eng, addr + 0x14, 0x00000000);
+ bar->flush(bar);
+
/* HW bug workaround:
*
* PFIFO will hang forever if the connected engines don't report
@@ -133,18 +141,8 @@ nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend,
if (suspend)
ret = -EBUSY;
}
- nv_wr32(priv, 0x00b860, me);
-
- if (ret == 0) {
- nv_wo32(base->eng, addr + 0x00, 0x00000000);
- nv_wo32(base->eng, addr + 0x04, 0x00000000);
- nv_wo32(base->eng, addr + 0x08, 0x00000000);
- nv_wo32(base->eng, addr + 0x0c, 0x00000000);
- nv_wo32(base->eng, addr + 0x10, 0x00000000);
- nv_wo32(base->eng, addr + 0x14, 0x00000000);
- bar->flush(bar);
- }
+ nv_wr32(priv, 0x00b860, me);
return ret;
}
@@ -196,10 +194,10 @@ nv50_fifo_chan_ctor_dma(struct nouveau_object *parent,
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x2000, args->pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG), &chan);
+ (1 << NVDEV_ENGINE_DMAOBJ) |
+ (1 << NVDEV_ENGINE_SW) |
+ (1 << NVDEV_ENGINE_GR) |
+ (1 << NVDEV_ENGINE_MPEG), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
@@ -249,10 +247,10 @@ nv50_fifo_chan_ctor_ind(struct nouveau_object *parent,
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x2000, args->pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG), &chan);
+ (1 << NVDEV_ENGINE_DMAOBJ) |
+ (1 << NVDEV_ENGINE_SW) |
+ (1 << NVDEV_ENGINE_GR) |
+ (1 << NVDEV_ENGINE_MPEG), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
index 1eb1c512f503..b4fd26d8f166 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
@@ -95,6 +95,14 @@ nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
return -EINVAL;
}
+ nv_wo32(base->eng, addr + 0x00, 0x00000000);
+ nv_wo32(base->eng, addr + 0x04, 0x00000000);
+ nv_wo32(base->eng, addr + 0x08, 0x00000000);
+ nv_wo32(base->eng, addr + 0x0c, 0x00000000);
+ nv_wo32(base->eng, addr + 0x10, 0x00000000);
+ nv_wo32(base->eng, addr + 0x14, 0x00000000);
+ bar->flush(bar);
+
save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn);
nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff);
@@ -104,14 +112,6 @@ nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
if (suspend)
return -EBUSY;
}
-
- nv_wo32(base->eng, addr + 0x00, 0x00000000);
- nv_wo32(base->eng, addr + 0x04, 0x00000000);
- nv_wo32(base->eng, addr + 0x08, 0x00000000);
- nv_wo32(base->eng, addr + 0x0c, 0x00000000);
- nv_wo32(base->eng, addr + 0x10, 0x00000000);
- nv_wo32(base->eng, addr + 0x14, 0x00000000);
- bar->flush(bar);
return 0;
}
@@ -163,17 +163,17 @@ nv84_fifo_chan_ctor_dma(struct nouveau_object *parent,
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x2000, args->pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG) |
- (1ULL << NVDEV_ENGINE_ME) |
- (1ULL << NVDEV_ENGINE_VP) |
- (1ULL << NVDEV_ENGINE_CRYPT) |
- (1ULL << NVDEV_ENGINE_BSP) |
- (1ULL << NVDEV_ENGINE_PPP) |
- (1ULL << NVDEV_ENGINE_COPY0) |
- (1ULL << NVDEV_ENGINE_UNK1C1), &chan);
+ (1 << NVDEV_ENGINE_DMAOBJ) |
+ (1 << NVDEV_ENGINE_SW) |
+ (1 << NVDEV_ENGINE_GR) |
+ (1 << NVDEV_ENGINE_MPEG) |
+ (1 << NVDEV_ENGINE_ME) |
+ (1 << NVDEV_ENGINE_VP) |
+ (1 << NVDEV_ENGINE_CRYPT) |
+ (1 << NVDEV_ENGINE_BSP) |
+ (1 << NVDEV_ENGINE_PPP) |
+ (1 << NVDEV_ENGINE_COPY0) |
+ (1 << NVDEV_ENGINE_UNK1C1), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
@@ -225,17 +225,17 @@ nv84_fifo_chan_ctor_ind(struct nouveau_object *parent,
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x2000, args->pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG) |
- (1ULL << NVDEV_ENGINE_ME) |
- (1ULL << NVDEV_ENGINE_VP) |
- (1ULL << NVDEV_ENGINE_CRYPT) |
- (1ULL << NVDEV_ENGINE_BSP) |
- (1ULL << NVDEV_ENGINE_PPP) |
- (1ULL << NVDEV_ENGINE_COPY0) |
- (1ULL << NVDEV_ENGINE_UNK1C1), &chan);
+ (1 << NVDEV_ENGINE_DMAOBJ) |
+ (1 << NVDEV_ENGINE_SW) |
+ (1 << NVDEV_ENGINE_GR) |
+ (1 << NVDEV_ENGINE_MPEG) |
+ (1 << NVDEV_ENGINE_ME) |
+ (1 << NVDEV_ENGINE_VP) |
+ (1 << NVDEV_ENGINE_CRYPT) |
+ (1 << NVDEV_ENGINE_BSP) |
+ (1 << NVDEV_ENGINE_PPP) |
+ (1 << NVDEV_ENGINE_COPY0) |
+ (1 << NVDEV_ENGINE_UNK1C1), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
index b4365dde1859..6f21be600557 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
@@ -103,9 +103,6 @@ nvc0_fifo_context_attach(struct nouveau_object *parent,
case NVDEV_ENGINE_GR : addr = 0x0210; break;
case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
- case NVDEV_ENGINE_BSP : addr = 0x0270; break;
- case NVDEV_ENGINE_VP : addr = 0x0250; break;
- case NVDEV_ENGINE_PPP : addr = 0x0260; break;
default:
return -EINVAL;
}
@@ -140,13 +137,14 @@ nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
case NVDEV_ENGINE_GR : addr = 0x0210; break;
case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
- case NVDEV_ENGINE_BSP : addr = 0x0270; break;
- case NVDEV_ENGINE_VP : addr = 0x0250; break;
- case NVDEV_ENGINE_PPP : addr = 0x0260; break;
default:
return -EINVAL;
}
+ nv_wo32(base, addr + 0x00, 0x00000000);
+ nv_wo32(base, addr + 0x04, 0x00000000);
+ bar->flush(bar);
+
nv_wr32(priv, 0x002634, chan->base.chid);
if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
nv_error(priv, "channel %d kick timeout\n", chan->base.chid);
@@ -154,9 +152,6 @@ nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
return -EBUSY;
}
- nv_wo32(base, addr + 0x00, 0x00000000);
- nv_wo32(base, addr + 0x04, 0x00000000);
- bar->flush(bar);
return 0;
}
@@ -180,13 +175,10 @@ nvc0_fifo_chan_ctor(struct nouveau_object *parent,
ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
priv->user.bar.offset, 0x1000,
args->pushbuf,
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_COPY0) |
- (1ULL << NVDEV_ENGINE_COPY1) |
- (1ULL << NVDEV_ENGINE_BSP) |
- (1ULL << NVDEV_ENGINE_VP) |
- (1ULL << NVDEV_ENGINE_PPP), &chan);
+ (1 << NVDEV_ENGINE_SW) |
+ (1 << NVDEV_ENGINE_GR) |
+ (1 << NVDEV_ENGINE_COPY0) |
+ (1 << NVDEV_ENGINE_COPY1), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
@@ -502,7 +494,7 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
u32 stat = nv_rd32(priv, 0x002100) & mask;
if (stat & 0x00000100) {
- nv_warn(priv, "unknown status 0x00000100\n");
+ nv_info(priv, "unknown status 0x00000100\n");
nv_wr32(priv, 0x002100, 0x00000100);
stat &= ~0x00000100;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index c930da99c2c1..36e81b6fafbc 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -38,12 +38,12 @@
#include
#include
-#define _(a,b) { (a), ((1ULL << (a)) | (b)) }
+#define _(a,b) { (a), ((1 << (a)) | (b)) }
static const struct {
- u64 subdev;
- u64 mask;
+ int subdev;
+ u32 mask;
} fifo_engine[] = {
- _(NVDEV_ENGINE_GR , (1ULL << NVDEV_ENGINE_SW)),
+ _(NVDEV_ENGINE_GR , (1 << NVDEV_ENGINE_SW)),
_(NVDEV_ENGINE_VP , 0),
_(NVDEV_ENGINE_PPP , 0),
_(NVDEV_ENGINE_BSP , 0),
@@ -138,9 +138,6 @@ nve0_fifo_context_attach(struct nouveau_object *parent,
case NVDEV_ENGINE_GR :
case NVDEV_ENGINE_COPY0:
case NVDEV_ENGINE_COPY1: addr = 0x0210; break;
- case NVDEV_ENGINE_BSP : addr = 0x0270; break;
- case NVDEV_ENGINE_VP : addr = 0x0250; break;
- case NVDEV_ENGINE_PPP : addr = 0x0260; break;
default:
return -EINVAL;
}
@@ -175,13 +172,14 @@ nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
case NVDEV_ENGINE_GR :
case NVDEV_ENGINE_COPY0:
case NVDEV_ENGINE_COPY1: addr = 0x0210; break;
- case NVDEV_ENGINE_BSP : addr = 0x0270; break;
- case NVDEV_ENGINE_VP : addr = 0x0250; break;
- case NVDEV_ENGINE_PPP : addr = 0x0260; break;
default:
return -EINVAL;
}
+ nv_wo32(base, addr + 0x00, 0x00000000);
+ nv_wo32(base, addr + 0x04, 0x00000000);
+ bar->flush(bar);
+
nv_wr32(priv, 0x002634, chan->base.chid);
if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
nv_error(priv, "channel %d kick timeout\n", chan->base.chid);
@@ -189,9 +187,6 @@ nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
return -EBUSY;
}
- nv_wo32(base, addr + 0x00, 0x00000000);
- nv_wo32(base, addr + 0x04, 0x00000000);
- bar->flush(bar);
return 0;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
index e30a9c5ff1fc..618528248457 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
@@ -787,168 +787,168 @@ nv01_graph_mthd_bind_chroma(struct nouveau_object *object, u32 mthd,
static struct nouveau_omthds
nv03_graph_gdi_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_patt },
- { 0x0188, 0x0188, nv04_graph_mthd_bind_rop },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_beta1 },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
+ { 0x0184, nv01_graph_mthd_bind_patt },
+ { 0x0188, nv04_graph_mthd_bind_rop },
+ { 0x018c, nv04_graph_mthd_bind_beta1 },
+ { 0x0190, nv04_graph_mthd_bind_surf_dst },
+ { 0x02fc, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv04_graph_gdi_omthds[] = {
- { 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
+ { 0x0188, nv04_graph_mthd_bind_patt },
+ { 0x018c, nv04_graph_mthd_bind_rop },
+ { 0x0190, nv04_graph_mthd_bind_beta1 },
+ { 0x0194, nv04_graph_mthd_bind_beta4 },
+ { 0x0198, nv04_graph_mthd_bind_surf2d },
+ { 0x02fc, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv01_graph_blit_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
- { 0x018c, 0x018c, nv01_graph_mthd_bind_patt },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf_dst },
- { 0x019c, 0x019c, nv04_graph_mthd_bind_surf_src },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
+ { 0x0184, nv01_graph_mthd_bind_chroma },
+ { 0x0188, nv01_graph_mthd_bind_clip },
+ { 0x018c, nv01_graph_mthd_bind_patt },
+ { 0x0190, nv04_graph_mthd_bind_rop },
+ { 0x0194, nv04_graph_mthd_bind_beta1 },
+ { 0x0198, nv04_graph_mthd_bind_surf_dst },
+ { 0x019c, nv04_graph_mthd_bind_surf_src },
+ { 0x02fc, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv04_graph_blit_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_patt },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_beta4 },
- { 0x019c, 0x019c, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
+ { 0x0184, nv01_graph_mthd_bind_chroma },
+ { 0x0188, nv01_graph_mthd_bind_clip },
+ { 0x018c, nv04_graph_mthd_bind_patt },
+ { 0x0190, nv04_graph_mthd_bind_rop },
+ { 0x0194, nv04_graph_mthd_bind_beta1 },
+ { 0x0198, nv04_graph_mthd_bind_beta4 },
+ { 0x019c, nv04_graph_mthd_bind_surf2d },
+ { 0x02fc, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv04_graph_iifc_omthds[] = {
- { 0x0188, 0x0188, nv01_graph_mthd_bind_chroma },
- { 0x018c, 0x018c, nv01_graph_mthd_bind_clip },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_patt },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_rop },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_beta1 },
- { 0x019c, 0x019c, nv04_graph_mthd_bind_beta4 },
- { 0x01a0, 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf },
- { 0x03e4, 0x03e4, nv04_graph_mthd_set_operation },
+ { 0x0188, nv01_graph_mthd_bind_chroma },
+ { 0x018c, nv01_graph_mthd_bind_clip },
+ { 0x0190, nv04_graph_mthd_bind_patt },
+ { 0x0194, nv04_graph_mthd_bind_rop },
+ { 0x0198, nv04_graph_mthd_bind_beta1 },
+ { 0x019c, nv04_graph_mthd_bind_beta4 },
+ { 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf },
+ { 0x03e4, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv01_graph_ifc_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
- { 0x018c, 0x018c, nv01_graph_mthd_bind_patt },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
+ { 0x0184, nv01_graph_mthd_bind_chroma },
+ { 0x0188, nv01_graph_mthd_bind_clip },
+ { 0x018c, nv01_graph_mthd_bind_patt },
+ { 0x0190, nv04_graph_mthd_bind_rop },
+ { 0x0194, nv04_graph_mthd_bind_beta1 },
+ { 0x0198, nv04_graph_mthd_bind_surf_dst },
+ { 0x02fc, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv04_graph_ifc_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_patt },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_beta4 },
- { 0x019c, 0x019c, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
+ { 0x0184, nv01_graph_mthd_bind_chroma },
+ { 0x0188, nv01_graph_mthd_bind_clip },
+ { 0x018c, nv04_graph_mthd_bind_patt },
+ { 0x0190, nv04_graph_mthd_bind_rop },
+ { 0x0194, nv04_graph_mthd_bind_beta1 },
+ { 0x0198, nv04_graph_mthd_bind_beta4 },
+ { 0x019c, nv04_graph_mthd_bind_surf2d },
+ { 0x02fc, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv03_graph_sifc_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
+ { 0x0184, nv01_graph_mthd_bind_chroma },
+ { 0x0188, nv01_graph_mthd_bind_patt },
+ { 0x018c, nv04_graph_mthd_bind_rop },
+ { 0x0190, nv04_graph_mthd_bind_beta1 },
+ { 0x0194, nv04_graph_mthd_bind_surf_dst },
+ { 0x02fc, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv04_graph_sifc_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
+ { 0x0184, nv01_graph_mthd_bind_chroma },
+ { 0x0188, nv04_graph_mthd_bind_patt },
+ { 0x018c, nv04_graph_mthd_bind_rop },
+ { 0x0190, nv04_graph_mthd_bind_beta1 },
+ { 0x0194, nv04_graph_mthd_bind_beta4 },
+ { 0x0198, nv04_graph_mthd_bind_surf2d },
+ { 0x02fc, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv03_graph_sifm_omthds[] = {
- { 0x0188, 0x0188, nv01_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_surf_dst },
- { 0x0304, 0x0304, nv04_graph_mthd_set_operation },
+ { 0x0188, nv01_graph_mthd_bind_patt },
+ { 0x018c, nv04_graph_mthd_bind_rop },
+ { 0x0190, nv04_graph_mthd_bind_beta1 },
+ { 0x0194, nv04_graph_mthd_bind_surf_dst },
+ { 0x0304, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv04_graph_sifm_omthds[] = {
- { 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x0304, 0x0304, nv04_graph_mthd_set_operation },
+ { 0x0188, nv04_graph_mthd_bind_patt },
+ { 0x018c, nv04_graph_mthd_bind_rop },
+ { 0x0190, nv04_graph_mthd_bind_beta1 },
+ { 0x0194, nv04_graph_mthd_bind_beta4 },
+ { 0x0198, nv04_graph_mthd_bind_surf2d },
+ { 0x0304, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv04_graph_surf3d_omthds[] = {
- { 0x02f8, 0x02f8, nv04_graph_mthd_surf3d_clip_h },
- { 0x02fc, 0x02fc, nv04_graph_mthd_surf3d_clip_v },
+ { 0x02f8, nv04_graph_mthd_surf3d_clip_h },
+ { 0x02fc, nv04_graph_mthd_surf3d_clip_v },
{}
};
static struct nouveau_omthds
nv03_graph_ttri_omthds[] = {
- { 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_surf_color },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_surf_zeta },
+ { 0x0188, nv01_graph_mthd_bind_clip },
+ { 0x018c, nv04_graph_mthd_bind_surf_color },
+ { 0x0190, nv04_graph_mthd_bind_surf_zeta },
{}
};
static struct nouveau_omthds
nv01_graph_prim_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_clip },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
+ { 0x0184, nv01_graph_mthd_bind_clip },
+ { 0x0188, nv01_graph_mthd_bind_patt },
+ { 0x018c, nv04_graph_mthd_bind_rop },
+ { 0x0190, nv04_graph_mthd_bind_beta1 },
+ { 0x0194, nv04_graph_mthd_bind_surf_dst },
+ { 0x02fc, nv04_graph_mthd_set_operation },
{}
};
static struct nouveau_omthds
nv04_graph_prim_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_clip },
- { 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
+ { 0x0184, nv01_graph_mthd_bind_clip },
+ { 0x0188, nv04_graph_mthd_bind_patt },
+ { 0x018c, nv04_graph_mthd_bind_rop },
+ { 0x0190, nv04_graph_mthd_bind_beta1 },
+ { 0x0194, nv04_graph_mthd_bind_beta4 },
+ { 0x0198, nv04_graph_mthd_bind_surf2d },
+ { 0x02fc, nv04_graph_mthd_set_operation },
{}
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
index 5c0f843ea249..92521c89e77f 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
@@ -570,11 +570,11 @@ nv17_graph_mthd_lma_enable(struct nouveau_object *object, u32 mthd,
static struct nouveau_omthds
nv17_celcius_omthds[] = {
- { 0x1638, 0x1638, nv17_graph_mthd_lma_window },
- { 0x163c, 0x163c, nv17_graph_mthd_lma_window },
- { 0x1640, 0x1640, nv17_graph_mthd_lma_window },
- { 0x1644, 0x1644, nv17_graph_mthd_lma_window },
- { 0x1658, 0x1658, nv17_graph_mthd_lma_enable },
+ { 0x1638, nv17_graph_mthd_lma_window },
+ { 0x163c, nv17_graph_mthd_lma_window },
+ { 0x1640, nv17_graph_mthd_lma_window },
+ { 0x1644, nv17_graph_mthd_lma_window },
+ { 0x1658, nv17_graph_mthd_lma_enable },
{}
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
index 5b20401bf911..8f3f619c4a78 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
@@ -183,7 +183,7 @@ nv20_graph_tile_prog(struct nouveau_engine *engine, int i)
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr);
- if (nv_device(engine)->chipset != 0x34) {
+ if (nv_device(engine)->card_type == NV_20) {
nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp);
@@ -224,14 +224,14 @@ nv20_graph_intr(struct nouveau_subdev *subdev)
nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
if (show) {
- nv_error(priv, "");
+ nv_info(priv, "");
nouveau_bitfield_print(nv10_graph_intr_name, show);
printk(" nsource:");
nouveau_bitfield_print(nv04_graph_nsource, nsource);
printk(" nstatus:");
nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
printk("\n");
- nv_error(priv, "ch %d/%d class 0x%04x mthd 0x%04x data 0x%08x\n",
+ nv_info(priv, "ch %d/%d class 0x%04x mthd 0x%04x data 0x%08x\n",
chid, subc, class, mthd, data);
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
index 8fc1221408b2..8d0021049ec0 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
@@ -216,10 +216,10 @@ nv40_graph_tile_prog(struct nouveau_engine *engine, int i)
switch (nv_device(priv)->chipset) {
case 0x40:
- case 0x41:
+ case 0x41: /* guess */
case 0x42:
case 0x43:
- case 0x45:
+ case 0x45: /* guess */
case 0x4e:
nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
@@ -227,21 +227,6 @@ nv40_graph_tile_prog(struct nouveau_engine *engine, int i)
nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
- switch (nv_device(priv)->chipset) {
- case 0x40:
- case 0x45:
- nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
- nv_wr32(priv, NV40_PGRAPH_ZCOMP1(i), tile->zcomp);
- break;
- case 0x41:
- case 0x42:
- case 0x43:
- nv_wr32(priv, NV41_PGRAPH_ZCOMP0(i), tile->zcomp);
- nv_wr32(priv, NV41_PGRAPH_ZCOMP1(i), tile->zcomp);
- break;
- default:
- break;
- }
break;
case 0x44:
case 0x4a:
@@ -250,31 +235,18 @@ nv40_graph_tile_prog(struct nouveau_engine *engine, int i)
nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
break;
case 0x46:
- case 0x4c:
case 0x47:
case 0x49:
case 0x4b:
- case 0x63:
+ case 0x4c:
case 0x67:
- case 0x68:
+ default:
nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr);
nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
- switch (nv_device(priv)->chipset) {
- case 0x47:
- case 0x49:
- case 0x4b:
- nv_wr32(priv, NV47_PGRAPH_ZCOMP0(i), tile->zcomp);
- nv_wr32(priv, NV47_PGRAPH_ZCOMP1(i), tile->zcomp);
- break;
- default:
- break;
- }
- break;
- default:
break;
}
@@ -321,7 +293,7 @@ nv40_graph_intr(struct nouveau_subdev *subdev)
nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
if (show) {
- nv_error(priv, "");
+ nv_info(priv, "");
nouveau_bitfield_print(nv10_graph_intr_name, show);
printk(" nsource:");
nouveau_bitfield_print(nv04_graph_nsource, nsource);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
index b1c3d835b4c2..ab3b9dcaf478 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
@@ -184,65 +184,6 @@ nv50_graph_tlb_flush(struct nouveau_engine *engine)
return 0;
}
-static const struct nouveau_bitfield nv50_pgraph_status[] = {
- { 0x00000001, "BUSY" }, /* set when any bit is set */
- { 0x00000002, "DISPATCH" },
- { 0x00000004, "UNK2" },
- { 0x00000008, "UNK3" },
- { 0x00000010, "UNK4" },
- { 0x00000020, "UNK5" },
- { 0x00000040, "M2MF" },
- { 0x00000080, "UNK7" },
- { 0x00000100, "CTXPROG" },
- { 0x00000200, "VFETCH" },
- { 0x00000400, "CCACHE_UNK4" },
- { 0x00000800, "STRMOUT_GSCHED_UNK5" },
- { 0x00001000, "UNK14XX" },
- { 0x00002000, "UNK24XX_CSCHED" },
- { 0x00004000, "UNK1CXX" },
- { 0x00008000, "CLIPID" },
- { 0x00010000, "ZCULL" },
- { 0x00020000, "ENG2D" },
- { 0x00040000, "UNK34XX" },
- { 0x00080000, "TPRAST" },
- { 0x00100000, "TPROP" },
- { 0x00200000, "TEX" },
- { 0x00400000, "TPVP" },
- { 0x00800000, "MP" },
- { 0x01000000, "ROP" },
- {}
-};
-
-static const char *const nv50_pgraph_vstatus_0[] = {
- "VFETCH", "CCACHE", "UNK4", "UNK5", "GSCHED", "STRMOUT", "UNK14XX", NULL
-};
-
-static const char *const nv50_pgraph_vstatus_1[] = {
- "TPRAST", "TPROP", "TEXTURE", "TPVP", "MP", NULL
-};
-
-static const char *const nv50_pgraph_vstatus_2[] = {
- "UNK24XX", "CSCHED", "UNK1CXX", "CLIPID", "ZCULL", "ENG2D", "UNK34XX",
- "ROP", NULL
-};
-
-static void nouveau_pgraph_vstatus_print(struct nv50_graph_priv *priv, int r,
- const char *const units[], u32 status)
-{
- int i;
-
- nv_error(priv, "PGRAPH_VSTATUS%d: 0x%08x", r, status);
-
- for (i = 0; units[i] && status; i++) {
- if ((status & 7) == 1)
- pr_cont(" %s", units[i]);
- status >>= 3;
- }
- if (status)
- pr_cont(" (invalid: 0x%x)", status);
- pr_cont("\n");
-}
-
static int
nv84_graph_tlb_flush(struct nouveau_engine *engine)
{
@@ -278,19 +219,10 @@ nv84_graph_tlb_flush(struct nouveau_engine *engine)
!(timeout = ptimer->read(ptimer) - start > 2000000000));
if (timeout) {
- nv_error(priv, "PGRAPH TLB flush idle timeout fail\n");
-
- tmp = nv_rd32(priv, 0x400700);
- nv_error(priv, "PGRAPH_STATUS : 0x%08x", tmp);
- nouveau_bitfield_print(nv50_pgraph_status, tmp);
- pr_cont("\n");
-
- nouveau_pgraph_vstatus_print(priv, 0, nv50_pgraph_vstatus_0,
- nv_rd32(priv, 0x400380));
- nouveau_pgraph_vstatus_print(priv, 1, nv50_pgraph_vstatus_1,
- nv_rd32(priv, 0x400384));
- nouveau_pgraph_vstatus_print(priv, 2, nv50_pgraph_vstatus_2,
- nv_rd32(priv, 0x400388));
+ nv_error(priv, "PGRAPH TLB flush idle timeout fail: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ nv_rd32(priv, 0x400700), nv_rd32(priv, 0x400380),
+ nv_rd32(priv, 0x400384), nv_rd32(priv, 0x400388));
}
nv50_vm_flush_engine(&engine->base, 0x00);
@@ -521,13 +453,13 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
}
if (ustatus) {
if (display)
- nv_error(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
+ nv_info(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
}
nv_wr32(priv, ustatus_addr, 0xc0000000);
}
if (!tps && display)
- nv_warn(priv, "%s - No TPs claiming errors?\n", name);
+ nv_info(priv, "%s - No TPs claiming errors?\n", name);
}
static int
@@ -786,12 +718,13 @@ nv50_graph_intr(struct nouveau_subdev *subdev)
nv_wr32(priv, 0x400500, 0x00010001);
if (show) {
- nv_error(priv, "");
+ nv_info(priv, "");
nouveau_bitfield_print(nv50_graph_intr_name, show);
printk("\n");
nv_error(priv, "ch %d [0x%010llx] subc %d class 0x%04x "
"mthd 0x%04x data 0x%08x\n",
chid, (u64)inst << 12, subc, class, mthd, data);
+ nv50_fb_trap(nouveau_fb(priv), 1);
}
if (nv_rd32(priv, 0x400824) & (1 << 31))
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
index 47a02081d708..c62f2d0f5f0a 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
@@ -814,7 +814,7 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
nv_wr32(priv, 0x41a100, 0x00000002);
nv_wr32(priv, 0x409100, 0x00000002);
if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
- nv_warn(priv, "0x409800 wait failed\n");
+ nv_info(priv, "0x409800 wait failed\n");
nv_wr32(priv, 0x409840, 0xffffffff);
nv_wr32(priv, 0x409500, 0x7fffffff);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/regs.h b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
index fde8e24415e4..9c715a25cecb 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
@@ -205,7 +205,6 @@
#define NV20_PGRAPH_TSIZE(i) (0x00400908 + (i*16))
#define NV20_PGRAPH_TSTATUS(i) (0x0040090C + (i*16))
#define NV20_PGRAPH_ZCOMP(i) (0x00400980 + 4*(i))
-#define NV41_PGRAPH_ZCOMP0(i) (0x004009c0 + 4*(i))
#define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16))
#define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16))
#define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16))
@@ -217,7 +216,6 @@
#define NV47_PGRAPH_TSTATUS(i) (0x00400D0C + (i*16))
#define NV04_PGRAPH_V_RAM 0x00400D40
#define NV04_PGRAPH_W_RAM 0x00400D80
-#define NV47_PGRAPH_ZCOMP0(i) (0x00400e00 + 4*(i))
#define NV10_PGRAPH_COMBINER0_IN_ALPHA 0x00400E40
#define NV10_PGRAPH_COMBINER1_IN_ALPHA 0x00400E44
#define NV10_PGRAPH_COMBINER0_IN_RGB 0x00400E48
@@ -263,12 +261,9 @@
#define NV04_PGRAPH_DMA_B_OFFSET 0x00401098
#define NV04_PGRAPH_DMA_B_SIZE 0x0040109C
#define NV04_PGRAPH_DMA_B_Y_SIZE 0x004010A0
-#define NV47_PGRAPH_ZCOMP1(i) (0x004068c0 + 4*(i))
#define NV40_PGRAPH_TILE1(i) (0x00406900 + (i*16))
#define NV40_PGRAPH_TLIMIT1(i) (0x00406904 + (i*16))
#define NV40_PGRAPH_TSIZE1(i) (0x00406908 + (i*16))
#define NV40_PGRAPH_TSTATUS1(i) (0x0040690C + (i*16))
-#define NV40_PGRAPH_ZCOMP1(i) (0x00406980 + 4*(i))
-#define NV41_PGRAPH_ZCOMP1(i) (0x004069c0 + 4*(i))
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/trunk/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
index 9fd86375f4c4..1f394a2629e7 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
@@ -121,9 +121,9 @@ nv31_mpeg_ofuncs = {
static struct nouveau_omthds
nv31_mpeg_omthds[] = {
- { 0x0190, 0x0190, nv31_mpeg_mthd_dma },
- { 0x01a0, 0x01a0, nv31_mpeg_mthd_dma },
- { 0x01b0, 0x01b0, nv31_mpeg_mthd_dma },
+ { 0x0190, nv31_mpeg_mthd_dma },
+ { 0x01a0, nv31_mpeg_mthd_dma },
+ { 0x01b0, nv31_mpeg_mthd_dma },
{}
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
index bc7d12b30fc1..8678a9996d57 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
@@ -157,6 +157,7 @@ nv50_mpeg_intr(struct nouveau_subdev *subdev)
nv_wr32(priv, 0x00b100, stat);
nv_wr32(priv, 0x00b230, 0x00000001);
+ nv50_fb_trap(nouveau_fb(priv), 1);
}
static void
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c b/trunk/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
index 5a5b2a773ed7..50e7e0da1981 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
@@ -22,18 +22,18 @@
* Authors: Ben Skeggs
*/
-#include
-#include
+#include
#include
+#include
#include
struct nv98_ppp_priv {
- struct nouveau_engine base;
+ struct nouveau_ppp base;
};
struct nv98_ppp_chan {
- struct nouveau_engctx base;
+ struct nouveau_ppp_chan base;
};
/*******************************************************************************
@@ -49,16 +49,61 @@ nv98_ppp_sclass[] = {
* PPPP context
******************************************************************************/
+static int
+nv98_ppp_context_ctor(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nv98_ppp_chan *priv;
+ int ret;
+
+ ret = nouveau_ppp_context_create(parent, engine, oclass, NULL,
+ 0, 0, 0, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void
+nv98_ppp_context_dtor(struct nouveau_object *object)
+{
+ struct nv98_ppp_chan *priv = (void *)object;
+ nouveau_ppp_context_destroy(&priv->base);
+}
+
+static int
+nv98_ppp_context_init(struct nouveau_object *object)
+{
+ struct nv98_ppp_chan *priv = (void *)object;
+ int ret;
+
+ ret = nouveau_ppp_context_init(&priv->base);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+nv98_ppp_context_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nv98_ppp_chan *priv = (void *)object;
+ return nouveau_ppp_context_fini(&priv->base, suspend);
+}
+
static struct nouveau_oclass
nv98_ppp_cclass = {
.handle = NV_ENGCTX(PPP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_engctx_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
+ .ctor = nv98_ppp_context_ctor,
+ .dtor = nv98_ppp_context_dtor,
+ .init = nv98_ppp_context_init,
+ .fini = nv98_ppp_context_fini,
+ .rd32 = _nouveau_ppp_context_rd32,
+ .wr32 = _nouveau_ppp_context_wr32,
},
};
@@ -66,6 +111,11 @@ nv98_ppp_cclass = {
* PPPP engine/subdev functions
******************************************************************************/
+static void
+nv98_ppp_intr(struct nouveau_subdev *subdev)
+{
+}
+
static int
nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@@ -74,25 +124,52 @@ nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv98_ppp_priv *priv;
int ret;
- ret = nouveau_engine_create(parent, engine, oclass, true,
- "PPPP", "ppp", &priv);
+ ret = nouveau_ppp_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00400002;
+ nv_subdev(priv)->intr = nv98_ppp_intr;
nv_engine(priv)->cclass = &nv98_ppp_cclass;
nv_engine(priv)->sclass = nv98_ppp_sclass;
return 0;
}
+static void
+nv98_ppp_dtor(struct nouveau_object *object)
+{
+ struct nv98_ppp_priv *priv = (void *)object;
+ nouveau_ppp_destroy(&priv->base);
+}
+
+static int
+nv98_ppp_init(struct nouveau_object *object)
+{
+ struct nv98_ppp_priv *priv = (void *)object;
+ int ret;
+
+ ret = nouveau_ppp_init(&priv->base);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+nv98_ppp_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nv98_ppp_priv *priv = (void *)object;
+ return nouveau_ppp_fini(&priv->base, suspend);
+}
+
struct nouveau_oclass
nv98_ppp_oclass = {
.handle = NV_ENGINE(PPP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_ppp_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = _nouveau_engine_init,
- .fini = _nouveau_engine_fini,
+ .dtor = nv98_ppp_dtor,
+ .init = nv98_ppp_init,
+ .fini = nv98_ppp_fini,
},
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
deleted file mode 100644
index ebf0d860e2dd..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Maarten Lankhorst
- *
- * 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: Maarten Lankhorst
- */
-
-#include
-
-#include
-
-struct nvc0_ppp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * PPP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_ppp_sclass[] = {
- { 0x90b3, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PPPP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_ppp_cclass = {
- .handle = NV_ENGCTX(PPP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PPPP engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_ppp_init(struct nouveau_object *object)
-{
- struct nvc0_ppp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x086010, 0x0000fff2);
- nv_wr32(priv, 0x08601c, 0x0000fff2);
- return 0;
-}
-
-static int
-nvc0_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_ppp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x086000, true,
- "PPPP", "ppp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000002;
- nv_engine(priv)->cclass = &nvc0_ppp_cclass;
- nv_engine(priv)->sclass = nvc0_ppp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_ppp_oclass = {
- .handle = NV_ENGINE(PPP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_ppp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nvc0_ppp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv04.c b/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv04.c
index 2a859a31c30d..3ca4c3aa90b7 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv04.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv04.c
@@ -63,8 +63,8 @@ nv04_software_flip(struct nouveau_object *object, u32 mthd,
static struct nouveau_omthds
nv04_software_omthds[] = {
- { 0x0150, 0x0150, nv04_software_set_ref },
- { 0x0500, 0x0500, nv04_software_flip },
+ { 0x0150, nv04_software_set_ref },
+ { 0x0500, nv04_software_flip },
{}
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv10.c b/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv10.c
index a019364b1e13..6e699afbfdb7 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv10.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv10.c
@@ -52,7 +52,7 @@ nv10_software_flip(struct nouveau_object *object, u32 mthd,
static struct nouveau_omthds
nv10_software_omthds[] = {
- { 0x0500, 0x0500, nv10_software_flip },
+ { 0x0500, nv10_software_flip },
{}
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
index b0e7e1c01ce6..a2edcd38544a 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
@@ -117,11 +117,11 @@ nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd,
static struct nouveau_omthds
nv50_software_omthds[] = {
- { 0x018c, 0x018c, nv50_software_mthd_dma_vblsem },
- { 0x0400, 0x0400, nv50_software_mthd_vblsem_offset },
- { 0x0404, 0x0404, nv50_software_mthd_vblsem_value },
- { 0x0408, 0x0408, nv50_software_mthd_vblsem_release },
- { 0x0500, 0x0500, nv50_software_mthd_flip },
+ { 0x018c, nv50_software_mthd_dma_vblsem },
+ { 0x0400, nv50_software_mthd_vblsem_offset },
+ { 0x0404, nv50_software_mthd_vblsem_value },
+ { 0x0408, nv50_software_mthd_vblsem_release },
+ { 0x0500, nv50_software_mthd_flip },
{}
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
index 282a1cd1bc2f..b7b0d7e330d6 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
@@ -99,11 +99,11 @@ nvc0_software_mthd_flip(struct nouveau_object *object, u32 mthd,
static struct nouveau_omthds
nvc0_software_omthds[] = {
- { 0x0400, 0x0400, nvc0_software_mthd_vblsem_offset },
- { 0x0404, 0x0404, nvc0_software_mthd_vblsem_offset },
- { 0x0408, 0x0408, nvc0_software_mthd_vblsem_value },
- { 0x040c, 0x040c, nvc0_software_mthd_vblsem_release },
- { 0x0500, 0x0500, nvc0_software_mthd_flip },
+ { 0x0400, nvc0_software_mthd_vblsem_offset },
+ { 0x0404, nvc0_software_mthd_vblsem_offset },
+ { 0x0408, nvc0_software_mthd_vblsem_value },
+ { 0x040c, nvc0_software_mthd_vblsem_release },
+ { 0x0500, nvc0_software_mthd_flip },
{}
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c b/trunk/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
index 261cd96e6951..dd23c80e5405 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
@@ -22,13 +22,18 @@
* Authors: Ben Skeggs
*/
-#include
+#include
#include
+#include
#include
struct nv84_vp_priv {
- struct nouveau_engine base;
+ struct nouveau_vp base;
+};
+
+struct nv84_vp_chan {
+ struct nouveau_vp_chan base;
};
/*******************************************************************************
@@ -44,16 +49,61 @@ nv84_vp_sclass[] = {
* PVP context
******************************************************************************/
+static int
+nv84_vp_context_ctor(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nv84_vp_chan *priv;
+ int ret;
+
+ ret = nouveau_vp_context_create(parent, engine, oclass, NULL,
+ 0, 0, 0, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void
+nv84_vp_context_dtor(struct nouveau_object *object)
+{
+ struct nv84_vp_chan *priv = (void *)object;
+ nouveau_vp_context_destroy(&priv->base);
+}
+
+static int
+nv84_vp_context_init(struct nouveau_object *object)
+{
+ struct nv84_vp_chan *priv = (void *)object;
+ int ret;
+
+ ret = nouveau_vp_context_init(&priv->base);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+nv84_vp_context_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nv84_vp_chan *priv = (void *)object;
+ return nouveau_vp_context_fini(&priv->base, suspend);
+}
+
static struct nouveau_oclass
nv84_vp_cclass = {
.handle = NV_ENGCTX(VP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_engctx_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
+ .ctor = nv84_vp_context_ctor,
+ .dtor = nv84_vp_context_dtor,
+ .init = nv84_vp_context_init,
+ .fini = nv84_vp_context_fini,
+ .rd32 = _nouveau_vp_context_rd32,
+ .wr32 = _nouveau_vp_context_wr32,
},
};
@@ -61,6 +111,11 @@ nv84_vp_cclass = {
* PVP engine/subdev functions
******************************************************************************/
+static void
+nv84_vp_intr(struct nouveau_subdev *subdev)
+{
+}
+
static int
nv84_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@@ -69,25 +124,52 @@ nv84_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv84_vp_priv *priv;
int ret;
- ret = nouveau_engine_create(parent, engine, oclass, true,
- "PVP", "vp", &priv);
+ ret = nouveau_vp_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x01020000;
+ nv_subdev(priv)->intr = nv84_vp_intr;
nv_engine(priv)->cclass = &nv84_vp_cclass;
nv_engine(priv)->sclass = nv84_vp_sclass;
return 0;
}
+static void
+nv84_vp_dtor(struct nouveau_object *object)
+{
+ struct nv84_vp_priv *priv = (void *)object;
+ nouveau_vp_destroy(&priv->base);
+}
+
+static int
+nv84_vp_init(struct nouveau_object *object)
+{
+ struct nv84_vp_priv *priv = (void *)object;
+ int ret;
+
+ ret = nouveau_vp_init(&priv->base);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+nv84_vp_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nv84_vp_priv *priv = (void *)object;
+ return nouveau_vp_fini(&priv->base, suspend);
+}
+
struct nouveau_oclass
nv84_vp_oclass = {
.handle = NV_ENGINE(VP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_vp_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = _nouveau_engine_init,
- .fini = _nouveau_engine_fini,
+ .dtor = nv84_vp_dtor,
+ .init = nv84_vp_init,
+ .fini = nv84_vp_fini,
},
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
deleted file mode 100644
index f761949d7039..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Maarten Lankhorst
- *
- * 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: Maarten Lankhorst
- */
-
-#include
-
-#include
-
-struct nvc0_vp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * VP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_vp_sclass[] = {
- { 0x90b2, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PVP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_vp_cclass = {
- .handle = NV_ENGCTX(VP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PVP engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_vp_init(struct nouveau_object *object)
-{
- struct nvc0_vp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x085010, 0x0000fff2);
- nv_wr32(priv, 0x08501c, 0x0000fff2);
- return 0;
-}
-
-static int
-nvc0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_vp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x085000, true,
- "PVP", "vp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00020000;
- nv_engine(priv)->cclass = &nvc0_vp_cclass;
- nv_engine(priv)->sclass = nvc0_vp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_vp_oclass = {
- .handle = NV_ENGINE(VP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_vp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nvc0_vp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c b/trunk/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
deleted file mode 100644
index 2384ce5dbe16..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 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
-
-struct nve0_vp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * VP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_vp_sclass[] = {
- { 0x95b2, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PVP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_vp_cclass = {
- .handle = NV_ENGCTX(VP, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PVP engine/subdev functions
- ******************************************************************************/
-
-static int
-nve0_vp_init(struct nouveau_object *object)
-{
- struct nve0_vp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x085010, 0x0000fff2);
- nv_wr32(priv, 0x08501c, 0x0000fff2);
- return 0;
-}
-
-static int
-nve0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_vp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x085000, true,
- "PVP", "vp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00020000;
- nv_engine(priv)->cclass = &nve0_vp_cclass;
- nv_engine(priv)->sclass = nve0_vp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nve0_vp_oclass = {
- .handle = NV_ENGINE(VP, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_vp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nve0_vp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/core/class.h b/trunk/drivers/gpu/drm/nouveau/core/include/core/class.h
index 47c4b3a5bd3a..6180ae9800fc 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/core/class.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/core/class.h
@@ -23,7 +23,6 @@
#define NV_DEVICE_DISABLE_COPY0 0x0000008000000000ULL
#define NV_DEVICE_DISABLE_COPY1 0x0000010000000000ULL
#define NV_DEVICE_DISABLE_UNK1C1 0x0000020000000000ULL
-#define NV_DEVICE_DISABLE_VENC 0x0000040000000000ULL
struct nv_device_class {
u64 device; /* device identifier, ~0 for client default */
@@ -53,49 +52,11 @@ struct nv_device_class {
#define NV_DMA_ACCESS_WR 0x00000200
#define NV_DMA_ACCESS_RDWR 0x00000300
-/* NV50:NVC0 */
-#define NV50_DMA_CONF0_ENABLE 0x80000000
-#define NV50_DMA_CONF0_PRIV 0x00300000
-#define NV50_DMA_CONF0_PRIV_VM 0x00000000
-#define NV50_DMA_CONF0_PRIV_US 0x00100000
-#define NV50_DMA_CONF0_PRIV__S 0x00200000
-#define NV50_DMA_CONF0_PART 0x00030000
-#define NV50_DMA_CONF0_PART_VM 0x00000000
-#define NV50_DMA_CONF0_PART_256 0x00010000
-#define NV50_DMA_CONF0_PART_1KB 0x00020000
-#define NV50_DMA_CONF0_COMP 0x00000180
-#define NV50_DMA_CONF0_COMP_NONE 0x00000000
-#define NV50_DMA_CONF0_COMP_VM 0x00000180
-#define NV50_DMA_CONF0_TYPE 0x0000007f
-#define NV50_DMA_CONF0_TYPE_LINEAR 0x00000000
-#define NV50_DMA_CONF0_TYPE_VM 0x0000007f
-
-/* NVC0:NVD9 */
-#define NVC0_DMA_CONF0_ENABLE 0x80000000
-#define NVC0_DMA_CONF0_PRIV 0x00300000
-#define NVC0_DMA_CONF0_PRIV_VM 0x00000000
-#define NVC0_DMA_CONF0_PRIV_US 0x00100000
-#define NVC0_DMA_CONF0_PRIV__S 0x00200000
-#define NVC0_DMA_CONF0_UNKN /* PART? */ 0x00030000
-#define NVC0_DMA_CONF0_TYPE 0x000000ff
-#define NVC0_DMA_CONF0_TYPE_LINEAR 0x00000000
-#define NVC0_DMA_CONF0_TYPE_VM 0x000000ff
-
-/* NVD9- */
-#define NVD0_DMA_CONF0_ENABLE 0x80000000
-#define NVD0_DMA_CONF0_PAGE 0x00000400
-#define NVD0_DMA_CONF0_PAGE_LP 0x00000000
-#define NVD0_DMA_CONF0_PAGE_SP 0x00000400
-#define NVD0_DMA_CONF0_TYPE 0x000000ff
-#define NVD0_DMA_CONF0_TYPE_LINEAR 0x00000000
-#define NVD0_DMA_CONF0_TYPE_VM 0x000000ff
-
struct nv_dma_class {
u32 flags;
u32 pad0;
u64 start;
u64 limit;
- u32 conf0;
};
/* DMA FIFO channel classes
@@ -154,190 +115,4 @@ struct nve0_channel_ind_class {
u32 engine;
};
-/* 5070: NV50_DISP
- * 8270: NV84_DISP
- * 8370: NVA0_DISP
- * 8870: NV94_DISP
- * 8570: NVA3_DISP
- * 9070: NVD0_DISP
- * 9170: NVE0_DISP
- */
-
-#define NV50_DISP_CLASS 0x00005070
-#define NV84_DISP_CLASS 0x00008270
-#define NVA0_DISP_CLASS 0x00008370
-#define NV94_DISP_CLASS 0x00008870
-#define NVA3_DISP_CLASS 0x00008570
-#define NVD0_DISP_CLASS 0x00009070
-#define NVE0_DISP_CLASS 0x00009170
-
-#define NV50_DISP_SOR_MTHD 0x00010000
-#define NV50_DISP_SOR_MTHD_TYPE 0x0000f000
-#define NV50_DISP_SOR_MTHD_HEAD 0x00000018
-#define NV50_DISP_SOR_MTHD_LINK 0x00000004
-#define NV50_DISP_SOR_MTHD_OR 0x00000003
-
-#define NV50_DISP_SOR_PWR 0x00010000
-#define NV50_DISP_SOR_PWR_STATE 0x00000001
-#define NV50_DISP_SOR_PWR_STATE_ON 0x00000001
-#define NV50_DISP_SOR_PWR_STATE_OFF 0x00000000
-#define NVA3_DISP_SOR_HDA_ELD 0x00010100
-#define NV84_DISP_SOR_HDMI_PWR 0x00012000
-#define NV84_DISP_SOR_HDMI_PWR_STATE 0x40000000
-#define NV84_DISP_SOR_HDMI_PWR_STATE_OFF 0x00000000
-#define NV84_DISP_SOR_HDMI_PWR_STATE_ON 0x40000000
-#define NV84_DISP_SOR_HDMI_PWR_MAX_AC_PACKET 0x001f0000
-#define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f
-#define NV50_DISP_SOR_LVDS_SCRIPT 0x00013000
-#define NV50_DISP_SOR_LVDS_SCRIPT_ID 0x0000ffff
-#define NV94_DISP_SOR_DP_TRAIN 0x00016000
-#define NV94_DISP_SOR_DP_TRAIN_OP 0xf0000000
-#define NV94_DISP_SOR_DP_TRAIN_OP_PATTERN 0x00000000
-#define NV94_DISP_SOR_DP_TRAIN_OP_INIT 0x10000000
-#define NV94_DISP_SOR_DP_TRAIN_OP_FINI 0x20000000
-#define NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD 0x00000001
-#define NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_OFF 0x00000000
-#define NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_ON 0x00000001
-#define NV94_DISP_SOR_DP_TRAIN_PATTERN 0x00000003
-#define NV94_DISP_SOR_DP_TRAIN_PATTERN_DISABLED 0x00000000
-#define NV94_DISP_SOR_DP_LNKCTL 0x00016040
-#define NV94_DISP_SOR_DP_LNKCTL_FRAME 0x80000000
-#define NV94_DISP_SOR_DP_LNKCTL_FRAME_STD 0x00000000
-#define NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH 0x80000000
-#define NV94_DISP_SOR_DP_LNKCTL_WIDTH 0x00001f00
-#define NV94_DISP_SOR_DP_LNKCTL_COUNT 0x00000007
-#define NV94_DISP_SOR_DP_DRVCTL(l) ((l) * 0x40 + 0x00016100)
-#define NV94_DISP_SOR_DP_DRVCTL_VS 0x00000300
-#define NV94_DISP_SOR_DP_DRVCTL_PE 0x00000003
-
-#define NV50_DISP_DAC_MTHD 0x00020000
-#define NV50_DISP_DAC_MTHD_TYPE 0x0000f000
-#define NV50_DISP_DAC_MTHD_OR 0x00000003
-
-#define NV50_DISP_DAC_PWR 0x00020000
-#define NV50_DISP_DAC_PWR_HSYNC 0x00000001
-#define NV50_DISP_DAC_PWR_HSYNC_ON 0x00000000
-#define NV50_DISP_DAC_PWR_HSYNC_LO 0x00000001
-#define NV50_DISP_DAC_PWR_VSYNC 0x00000004
-#define NV50_DISP_DAC_PWR_VSYNC_ON 0x00000000
-#define NV50_DISP_DAC_PWR_VSYNC_LO 0x00000004
-#define NV50_DISP_DAC_PWR_DATA 0x00000010
-#define NV50_DISP_DAC_PWR_DATA_ON 0x00000000
-#define NV50_DISP_DAC_PWR_DATA_LO 0x00000010
-#define NV50_DISP_DAC_PWR_STATE 0x00000040
-#define NV50_DISP_DAC_PWR_STATE_ON 0x00000000
-#define NV50_DISP_DAC_PWR_STATE_OFF 0x00000040
-#define NV50_DISP_DAC_LOAD 0x0002000c
-#define NV50_DISP_DAC_LOAD_VALUE 0x00000007
-
-struct nv50_display_class {
-};
-
-/* 507a: NV50_DISP_CURS
- * 827a: NV84_DISP_CURS
- * 837a: NVA0_DISP_CURS
- * 887a: NV94_DISP_CURS
- * 857a: NVA3_DISP_CURS
- * 907a: NVD0_DISP_CURS
- * 917a: NVE0_DISP_CURS
- */
-
-#define NV50_DISP_CURS_CLASS 0x0000507a
-#define NV84_DISP_CURS_CLASS 0x0000827a
-#define NVA0_DISP_CURS_CLASS 0x0000837a
-#define NV94_DISP_CURS_CLASS 0x0000887a
-#define NVA3_DISP_CURS_CLASS 0x0000857a
-#define NVD0_DISP_CURS_CLASS 0x0000907a
-#define NVE0_DISP_CURS_CLASS 0x0000917a
-
-struct nv50_display_curs_class {
- u32 head;
-};
-
-/* 507b: NV50_DISP_OIMM
- * 827b: NV84_DISP_OIMM
- * 837b: NVA0_DISP_OIMM
- * 887b: NV94_DISP_OIMM
- * 857b: NVA3_DISP_OIMM
- * 907b: NVD0_DISP_OIMM
- * 917b: NVE0_DISP_OIMM
- */
-
-#define NV50_DISP_OIMM_CLASS 0x0000507b
-#define NV84_DISP_OIMM_CLASS 0x0000827b
-#define NVA0_DISP_OIMM_CLASS 0x0000837b
-#define NV94_DISP_OIMM_CLASS 0x0000887b
-#define NVA3_DISP_OIMM_CLASS 0x0000857b
-#define NVD0_DISP_OIMM_CLASS 0x0000907b
-#define NVE0_DISP_OIMM_CLASS 0x0000917b
-
-struct nv50_display_oimm_class {
- u32 head;
-};
-
-/* 507c: NV50_DISP_SYNC
- * 827c: NV84_DISP_SYNC
- * 837c: NVA0_DISP_SYNC
- * 887c: NV94_DISP_SYNC
- * 857c: NVA3_DISP_SYNC
- * 907c: NVD0_DISP_SYNC
- * 917c: NVE0_DISP_SYNC
- */
-
-#define NV50_DISP_SYNC_CLASS 0x0000507c
-#define NV84_DISP_SYNC_CLASS 0x0000827c
-#define NVA0_DISP_SYNC_CLASS 0x0000837c
-#define NV94_DISP_SYNC_CLASS 0x0000887c
-#define NVA3_DISP_SYNC_CLASS 0x0000857c
-#define NVD0_DISP_SYNC_CLASS 0x0000907c
-#define NVE0_DISP_SYNC_CLASS 0x0000917c
-
-struct nv50_display_sync_class {
- u32 pushbuf;
- u32 head;
-};
-
-/* 507d: NV50_DISP_MAST
- * 827d: NV84_DISP_MAST
- * 837d: NVA0_DISP_MAST
- * 887d: NV94_DISP_MAST
- * 857d: NVA3_DISP_MAST
- * 907d: NVD0_DISP_MAST
- * 917d: NVE0_DISP_MAST
- */
-
-#define NV50_DISP_MAST_CLASS 0x0000507d
-#define NV84_DISP_MAST_CLASS 0x0000827d
-#define NVA0_DISP_MAST_CLASS 0x0000837d
-#define NV94_DISP_MAST_CLASS 0x0000887d
-#define NVA3_DISP_MAST_CLASS 0x0000857d
-#define NVD0_DISP_MAST_CLASS 0x0000907d
-#define NVE0_DISP_MAST_CLASS 0x0000917d
-
-struct nv50_display_mast_class {
- u32 pushbuf;
-};
-
-/* 507e: NV50_DISP_OVLY
- * 827e: NV84_DISP_OVLY
- * 837e: NVA0_DISP_OVLY
- * 887e: NV94_DISP_OVLY
- * 857e: NVA3_DISP_OVLY
- * 907e: NVD0_DISP_OVLY
- * 917e: NVE0_DISP_OVLY
- */
-
-#define NV50_DISP_OVLY_CLASS 0x0000507e
-#define NV84_DISP_OVLY_CLASS 0x0000827e
-#define NVA0_DISP_OVLY_CLASS 0x0000837e
-#define NV94_DISP_OVLY_CLASS 0x0000887e
-#define NVA3_DISP_OVLY_CLASS 0x0000857e
-#define NVD0_DISP_OVLY_CLASS 0x0000907e
-#define NVE0_DISP_OVLY_CLASS 0x0000917e
-
-struct nv50_display_ovly_class {
- u32 pushbuf;
- u32 head;
-};
-
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/core/engctx.h b/trunk/drivers/gpu/drm/nouveau/core/include/core/engctx.h
index 2fd48b564c7d..8a947b6872eb 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/core/engctx.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/core/engctx.h
@@ -39,9 +39,6 @@ void nouveau_engctx_destroy(struct nouveau_engctx *);
int nouveau_engctx_init(struct nouveau_engctx *);
int nouveau_engctx_fini(struct nouveau_engctx *, bool suspend);
-int _nouveau_engctx_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
void _nouveau_engctx_dtor(struct nouveau_object *);
int _nouveau_engctx_init(struct nouveau_object *);
int _nouveau_engctx_fini(struct nouveau_object *, bool suspend);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/core/falcon.h b/trunk/drivers/gpu/drm/nouveau/core/include/core/falcon.h
deleted file mode 100644
index 1edec386ab36..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/include/core/falcon.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef __NOUVEAU_FALCON_H__
-#define __NOUVEAU_FALCON_H__
-
-#include
-#include
-#include
-
-struct nouveau_falcon_chan {
- struct nouveau_engctx base;
-};
-
-#define nouveau_falcon_context_create(p,e,c,g,s,a,f,d) \
- nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
-#define nouveau_falcon_context_destroy(d) \
- nouveau_engctx_destroy(&(d)->base)
-#define nouveau_falcon_context_init(d) \
- nouveau_engctx_init(&(d)->base)
-#define nouveau_falcon_context_fini(d,s) \
- nouveau_engctx_fini(&(d)->base, (s))
-
-#define _nouveau_falcon_context_ctor _nouveau_engctx_ctor
-#define _nouveau_falcon_context_dtor _nouveau_engctx_dtor
-#define _nouveau_falcon_context_init _nouveau_engctx_init
-#define _nouveau_falcon_context_fini _nouveau_engctx_fini
-#define _nouveau_falcon_context_rd32 _nouveau_engctx_rd32
-#define _nouveau_falcon_context_wr32 _nouveau_engctx_wr32
-
-struct nouveau_falcon_data {
- bool external;
-};
-
-struct nouveau_falcon {
- struct nouveau_engine base;
-
- u32 addr;
- u8 version;
- u8 secret;
-
- struct nouveau_gpuobj *core;
- bool external;
-
- struct {
- u32 limit;
- u32 *data;
- u32 size;
- } code;
-
- struct {
- u32 limit;
- u32 *data;
- u32 size;
- } data;
-};
-
-#define nv_falcon(priv) (&(priv)->base)
-
-#define nouveau_falcon_create(p,e,c,b,d,i,f,r) \
- nouveau_falcon_create_((p), (e), (c), (b), (d), (i), (f), \
- sizeof(**r),(void **)r)
-#define nouveau_falcon_destroy(p) \
- nouveau_engine_destroy(&(p)->base)
-#define nouveau_falcon_init(p) ({ \
- struct nouveau_falcon *falcon = (p); \
- _nouveau_falcon_init(nv_object(falcon)); \
-})
-#define nouveau_falcon_fini(p,s) ({ \
- struct nouveau_falcon *falcon = (p); \
- _nouveau_falcon_fini(nv_object(falcon), (s)); \
-})
-
-int nouveau_falcon_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, u32, bool, const char *,
- const char *, int, void **);
-
-#define _nouveau_falcon_dtor _nouveau_engine_dtor
-int _nouveau_falcon_init(struct nouveau_object *);
-int _nouveau_falcon_fini(struct nouveau_object *, bool);
-u32 _nouveau_falcon_rd32(struct nouveau_object *, u64);
-void _nouveau_falcon_wr32(struct nouveau_object *, u64, u32);
-
-#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h b/trunk/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h
index b3b9ce4e9d38..6eaff79377ae 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h
@@ -65,7 +65,7 @@ nouveau_gpuobj_ref(struct nouveau_gpuobj *obj, struct nouveau_gpuobj **ref)
void _nouveau_gpuobj_dtor(struct nouveau_object *);
int _nouveau_gpuobj_init(struct nouveau_object *);
int _nouveau_gpuobj_fini(struct nouveau_object *, bool);
-u32 _nouveau_gpuobj_rd32(struct nouveau_object *, u64);
-void _nouveau_gpuobj_wr32(struct nouveau_object *, u64, u32);
+u32 _nouveau_gpuobj_rd32(struct nouveau_object *, u32);
+void _nouveau_gpuobj_wr32(struct nouveau_object *, u32, u32);
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/core/mm.h b/trunk/drivers/gpu/drm/nouveau/core/include/core/mm.h
index 2514e81ade02..975137ba34a6 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/core/mm.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/core/mm.h
@@ -21,12 +21,6 @@ struct nouveau_mm {
int heap_nodes;
};
-static inline bool
-nouveau_mm_initialised(struct nouveau_mm *mm)
-{
- return mm->block_size != 0;
-}
-
int nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block);
int nouveau_mm_fini(struct nouveau_mm *);
int nouveau_mm_head(struct nouveau_mm *, u8 type, u32 size_max, u32 size_min,
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/core/object.h b/trunk/drivers/gpu/drm/nouveau/core/include/core/object.h
index 27d17a9852e5..818feabbf4a0 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/core/object.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/core/object.h
@@ -70,8 +70,7 @@ nv_pclass(struct nouveau_object *parent, u32 oclass)
}
struct nouveau_omthds {
- u32 start;
- u32 limit;
+ u32 method;
int (*call)(struct nouveau_object *, u32, void *, u32);
};
@@ -82,12 +81,12 @@ struct nouveau_ofuncs {
void (*dtor)(struct nouveau_object *);
int (*init)(struct nouveau_object *);
int (*fini)(struct nouveau_object *, bool suspend);
- u8 (*rd08)(struct nouveau_object *, u64 offset);
- u16 (*rd16)(struct nouveau_object *, u64 offset);
- u32 (*rd32)(struct nouveau_object *, u64 offset);
- void (*wr08)(struct nouveau_object *, u64 offset, u8 data);
- void (*wr16)(struct nouveau_object *, u64 offset, u16 data);
- void (*wr32)(struct nouveau_object *, u64 offset, u32 data);
+ u8 (*rd08)(struct nouveau_object *, u32 offset);
+ u16 (*rd16)(struct nouveau_object *, u32 offset);
+ u32 (*rd32)(struct nouveau_object *, u32 offset);
+ void (*wr08)(struct nouveau_object *, u32 offset, u8 data);
+ void (*wr16)(struct nouveau_object *, u32 offset, u16 data);
+ void (*wr32)(struct nouveau_object *, u32 offset, u32 data);
};
static inline struct nouveau_ofuncs *
@@ -110,27 +109,21 @@ int nouveau_object_del(struct nouveau_object *, u32 parent, u32 handle);
void nouveau_object_debug(void);
static inline int
-nv_exec(void *obj, u32 mthd, void *data, u32 size)
+nv_call(void *obj, u32 mthd, u32 data)
{
struct nouveau_omthds *method = nv_oclass(obj)->omthds;
while (method && method->call) {
- if (mthd >= method->start && mthd <= method->limit)
- return method->call(obj, mthd, data, size);
+ if (method->method == mthd)
+ return method->call(obj, mthd, &data, sizeof(data));
method++;
}
return -EINVAL;
}
-static inline int
-nv_call(void *obj, u32 mthd, u32 data)
-{
- return nv_exec(obj, mthd, &data, sizeof(data));
-}
-
static inline u8
-nv_ro08(void *obj, u64 addr)
+nv_ro08(void *obj, u32 addr)
{
u8 data = nv_ofuncs(obj)->rd08(obj, addr);
nv_spam(obj, "nv_ro08 0x%08x 0x%02x\n", addr, data);
@@ -138,7 +131,7 @@ nv_ro08(void *obj, u64 addr)
}
static inline u16
-nv_ro16(void *obj, u64 addr)
+nv_ro16(void *obj, u32 addr)
{
u16 data = nv_ofuncs(obj)->rd16(obj, addr);
nv_spam(obj, "nv_ro16 0x%08x 0x%04x\n", addr, data);
@@ -146,7 +139,7 @@ nv_ro16(void *obj, u64 addr)
}
static inline u32
-nv_ro32(void *obj, u64 addr)
+nv_ro32(void *obj, u32 addr)
{
u32 data = nv_ofuncs(obj)->rd32(obj, addr);
nv_spam(obj, "nv_ro32 0x%08x 0x%08x\n", addr, data);
@@ -154,28 +147,28 @@ nv_ro32(void *obj, u64 addr)
}
static inline void
-nv_wo08(void *obj, u64 addr, u8 data)
+nv_wo08(void *obj, u32 addr, u8 data)
{
nv_spam(obj, "nv_wo08 0x%08x 0x%02x\n", addr, data);
nv_ofuncs(obj)->wr08(obj, addr, data);
}
static inline void
-nv_wo16(void *obj, u64 addr, u16 data)
+nv_wo16(void *obj, u32 addr, u16 data)
{
nv_spam(obj, "nv_wo16 0x%08x 0x%04x\n", addr, data);
nv_ofuncs(obj)->wr16(obj, addr, data);
}
static inline void
-nv_wo32(void *obj, u64 addr, u32 data)
+nv_wo32(void *obj, u32 addr, u32 data)
{
nv_spam(obj, "nv_wo32 0x%08x 0x%08x\n", addr, data);
nv_ofuncs(obj)->wr32(obj, addr, data);
}
static inline u32
-nv_mo32(void *obj, u64 addr, u32 mask, u32 data)
+nv_mo32(void *obj, u32 addr, u32 mask, u32 data)
{
u32 temp = nv_ro32(obj, addr);
nv_wo32(obj, addr, (temp & ~mask) | data);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/core/parent.h b/trunk/drivers/gpu/drm/nouveau/core/include/core/parent.h
index 31cd852c96df..3c2e940eb0f8 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/core/parent.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/core/parent.h
@@ -14,7 +14,7 @@ struct nouveau_parent {
struct nouveau_object base;
struct nouveau_sclass *sclass;
- u64 engine;
+ u32 engine;
int (*context_attach)(struct nouveau_object *,
struct nouveau_object *);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/engine/bsp.h b/trunk/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
index 13ccdf54dfad..75d1ed5f85fd 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
@@ -1,8 +1,45 @@
#ifndef __NOUVEAU_BSP_H__
#define __NOUVEAU_BSP_H__
+#include
+#include
+
+struct nouveau_bsp_chan {
+ struct nouveau_engctx base;
+};
+
+#define nouveau_bsp_context_create(p,e,c,g,s,a,f,d) \
+ nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_bsp_context_destroy(d) \
+ nouveau_engctx_destroy(&(d)->base)
+#define nouveau_bsp_context_init(d) \
+ nouveau_engctx_init(&(d)->base)
+#define nouveau_bsp_context_fini(d,s) \
+ nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_bsp_context_dtor _nouveau_engctx_dtor
+#define _nouveau_bsp_context_init _nouveau_engctx_init
+#define _nouveau_bsp_context_fini _nouveau_engctx_fini
+#define _nouveau_bsp_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_bsp_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_bsp {
+ struct nouveau_engine base;
+};
+
+#define nouveau_bsp_create(p,e,c,d) \
+ nouveau_engine_create((p), (e), (c), true, "PBSP", "bsp", (d))
+#define nouveau_bsp_destroy(d) \
+ nouveau_engine_destroy(&(d)->base)
+#define nouveau_bsp_init(d) \
+ nouveau_engine_init(&(d)->base)
+#define nouveau_bsp_fini(d,s) \
+ nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_bsp_dtor _nouveau_engine_dtor
+#define _nouveau_bsp_init _nouveau_engine_init
+#define _nouveau_bsp_fini _nouveau_engine_fini
+
extern struct nouveau_oclass nv84_bsp_oclass;
-extern struct nouveau_oclass nvc0_bsp_oclass;
-extern struct nouveau_oclass nve0_bsp_oclass;
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/engine/copy.h b/trunk/drivers/gpu/drm/nouveau/core/include/engine/copy.h
index 8cad2cf28cef..70b9d8c5fcf5 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/engine/copy.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/engine/copy.h
@@ -1,7 +1,44 @@
#ifndef __NOUVEAU_COPY_H__
#define __NOUVEAU_COPY_H__
-void nva3_copy_intr(struct nouveau_subdev *);
+#include
+#include
+
+struct nouveau_copy_chan {
+ struct nouveau_engctx base;
+};
+
+#define nouveau_copy_context_create(p,e,c,g,s,a,f,d) \
+ nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_copy_context_destroy(d) \
+ nouveau_engctx_destroy(&(d)->base)
+#define nouveau_copy_context_init(d) \
+ nouveau_engctx_init(&(d)->base)
+#define nouveau_copy_context_fini(d,s) \
+ nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_copy_context_dtor _nouveau_engctx_dtor
+#define _nouveau_copy_context_init _nouveau_engctx_init
+#define _nouveau_copy_context_fini _nouveau_engctx_fini
+#define _nouveau_copy_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_copy_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_copy {
+ struct nouveau_engine base;
+};
+
+#define nouveau_copy_create(p,e,c,y,i,d) \
+ nouveau_engine_create((p), (e), (c), (y), "PCE"#i, "copy"#i, (d))
+#define nouveau_copy_destroy(d) \
+ nouveau_engine_destroy(&(d)->base)
+#define nouveau_copy_init(d) \
+ nouveau_engine_init(&(d)->base)
+#define nouveau_copy_fini(d,s) \
+ nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_copy_dtor _nouveau_engine_dtor
+#define _nouveau_copy_init _nouveau_engine_init
+#define _nouveau_copy_fini _nouveau_engine_fini
extern struct nouveau_oclass nva3_copy_oclass;
extern struct nouveau_oclass nvc0_copy0_oclass;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/engine/crypt.h b/trunk/drivers/gpu/drm/nouveau/core/include/engine/crypt.h
index db975618e937..e3674743baaa 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/engine/crypt.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/engine/crypt.h
@@ -1,6 +1,45 @@
#ifndef __NOUVEAU_CRYPT_H__
#define __NOUVEAU_CRYPT_H__
+#include
+#include
+
+struct nouveau_crypt_chan {
+ struct nouveau_engctx base;
+};
+
+#define nouveau_crypt_context_create(p,e,c,g,s,a,f,d) \
+ nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_crypt_context_destroy(d) \
+ nouveau_engctx_destroy(&(d)->base)
+#define nouveau_crypt_context_init(d) \
+ nouveau_engctx_init(&(d)->base)
+#define nouveau_crypt_context_fini(d,s) \
+ nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_crypt_context_dtor _nouveau_engctx_dtor
+#define _nouveau_crypt_context_init _nouveau_engctx_init
+#define _nouveau_crypt_context_fini _nouveau_engctx_fini
+#define _nouveau_crypt_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_crypt_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_crypt {
+ struct nouveau_engine base;
+};
+
+#define nouveau_crypt_create(p,e,c,d) \
+ nouveau_engine_create((p), (e), (c), true, "PCRYPT", "crypt", (d))
+#define nouveau_crypt_destroy(d) \
+ nouveau_engine_destroy(&(d)->base)
+#define nouveau_crypt_init(d) \
+ nouveau_engine_init(&(d)->base)
+#define nouveau_crypt_fini(d,s) \
+ nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_crypt_dtor _nouveau_engine_dtor
+#define _nouveau_crypt_init _nouveau_engine_init
+#define _nouveau_crypt_fini _nouveau_engine_fini
+
extern struct nouveau_oclass nv84_crypt_oclass;
extern struct nouveau_oclass nv98_crypt_oclass;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/trunk/drivers/gpu/drm/nouveau/core/include/engine/disp.h
index 46948285f3e7..38ec1252cbaa 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/engine/disp.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/engine/disp.h
@@ -39,11 +39,6 @@ nouveau_disp(void *obj)
extern struct nouveau_oclass nv04_disp_oclass;
extern struct nouveau_oclass nv50_disp_oclass;
-extern struct nouveau_oclass nv84_disp_oclass;
-extern struct nouveau_oclass nva0_disp_oclass;
-extern struct nouveau_oclass nv94_disp_oclass;
-extern struct nouveau_oclass nva3_disp_oclass;
extern struct nouveau_oclass nvd0_disp_oclass;
-extern struct nouveau_oclass nve0_disp_oclass;
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h b/trunk/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h
index b28914ed1752..700ccbb1941f 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h
@@ -12,17 +12,29 @@ struct nouveau_dmaobj {
u32 access;
u64 start;
u64 limit;
- u32 conf0;
};
+#define nouveau_dmaobj_create(p,e,c,a,s,d) \
+ nouveau_dmaobj_create_((p), (e), (c), (a), (s), sizeof(**d), (void **)d)
+#define nouveau_dmaobj_destroy(p) \
+ nouveau_object_destroy(&(p)->base)
+#define nouveau_dmaobj_init(p) \
+ nouveau_object_init(&(p)->base)
+#define nouveau_dmaobj_fini(p,s) \
+ nouveau_object_fini(&(p)->base, (s))
+
+int nouveau_dmaobj_create_(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, void *data, u32 size,
+ int length, void **);
+
+#define _nouveau_dmaobj_dtor nouveau_object_destroy
+#define _nouveau_dmaobj_init nouveau_object_init
+#define _nouveau_dmaobj_fini nouveau_object_fini
+
struct nouveau_dmaeng {
struct nouveau_engine base;
-
- /* creates a "physical" dma object from a struct nouveau_dmaobj */
- int (*bind)(struct nouveau_dmaeng *dmaeng,
- struct nouveau_object *parent,
- struct nouveau_dmaobj *dmaobj,
- struct nouveau_gpuobj **);
+ int (*bind)(struct nouveau_dmaeng *, struct nouveau_object *parent,
+ struct nouveau_dmaobj *, struct nouveau_gpuobj **);
};
#define nouveau_dmaeng_create(p,e,c,d) \
@@ -41,8 +53,5 @@ struct nouveau_dmaeng {
extern struct nouveau_oclass nv04_dmaeng_oclass;
extern struct nouveau_oclass nv50_dmaeng_oclass;
extern struct nouveau_oclass nvc0_dmaeng_oclass;
-extern struct nouveau_oclass nvd0_dmaeng_oclass;
-
-extern struct nouveau_oclass nouveau_dmaobj_sclass[];
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/engine/fifo.h b/trunk/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
index f18846c8c6fe..d67fed1e3970 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
@@ -33,15 +33,15 @@ int nouveau_fifo_channel_create_(struct nouveau_object *,
struct nouveau_object *,
struct nouveau_oclass *,
int bar, u32 addr, u32 size, u32 push,
- u64 engmask, int len, void **);
+ u32 engmask, int len, void **);
void nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *);
#define _nouveau_fifo_channel_init _nouveau_namedb_init
#define _nouveau_fifo_channel_fini _nouveau_namedb_fini
void _nouveau_fifo_channel_dtor(struct nouveau_object *);
-u32 _nouveau_fifo_channel_rd32(struct nouveau_object *, u64);
-void _nouveau_fifo_channel_wr32(struct nouveau_object *, u64, u32);
+u32 _nouveau_fifo_channel_rd32(struct nouveau_object *, u32);
+void _nouveau_fifo_channel_wr32(struct nouveau_object *, u32, u32);
struct nouveau_fifo_base {
struct nouveau_gpuobj base;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/engine/ppp.h b/trunk/drivers/gpu/drm/nouveau/core/include/engine/ppp.h
index 0a66781e8cf1..74d554fb3281 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/engine/ppp.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/engine/ppp.h
@@ -1,7 +1,45 @@
#ifndef __NOUVEAU_PPP_H__
#define __NOUVEAU_PPP_H__
+#include
+#include
+
+struct nouveau_ppp_chan {
+ struct nouveau_engctx base;
+};
+
+#define nouveau_ppp_context_create(p,e,c,g,s,a,f,d) \
+ nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_ppp_context_destroy(d) \
+ nouveau_engctx_destroy(&(d)->base)
+#define nouveau_ppp_context_init(d) \
+ nouveau_engctx_init(&(d)->base)
+#define nouveau_ppp_context_fini(d,s) \
+ nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_ppp_context_dtor _nouveau_engctx_dtor
+#define _nouveau_ppp_context_init _nouveau_engctx_init
+#define _nouveau_ppp_context_fini _nouveau_engctx_fini
+#define _nouveau_ppp_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_ppp_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_ppp {
+ struct nouveau_engine base;
+};
+
+#define nouveau_ppp_create(p,e,c,d) \
+ nouveau_engine_create((p), (e), (c), true, "PPPP", "ppp", (d))
+#define nouveau_ppp_destroy(d) \
+ nouveau_engine_destroy(&(d)->base)
+#define nouveau_ppp_init(d) \
+ nouveau_engine_init(&(d)->base)
+#define nouveau_ppp_fini(d,s) \
+ nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_ppp_dtor _nouveau_engine_dtor
+#define _nouveau_ppp_init _nouveau_engine_init
+#define _nouveau_ppp_fini _nouveau_engine_fini
+
extern struct nouveau_oclass nv98_ppp_oclass;
-extern struct nouveau_oclass nvc0_ppp_oclass;
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/engine/vp.h b/trunk/drivers/gpu/drm/nouveau/core/include/engine/vp.h
index d7b287b115bf..05cd08fba377 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/engine/vp.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/engine/vp.h
@@ -1,8 +1,45 @@
#ifndef __NOUVEAU_VP_H__
#define __NOUVEAU_VP_H__
+#include
+#include
+
+struct nouveau_vp_chan {
+ struct nouveau_engctx base;
+};
+
+#define nouveau_vp_context_create(p,e,c,g,s,a,f,d) \
+ nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_vp_context_destroy(d) \
+ nouveau_engctx_destroy(&(d)->base)
+#define nouveau_vp_context_init(d) \
+ nouveau_engctx_init(&(d)->base)
+#define nouveau_vp_context_fini(d,s) \
+ nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_vp_context_dtor _nouveau_engctx_dtor
+#define _nouveau_vp_context_init _nouveau_engctx_init
+#define _nouveau_vp_context_fini _nouveau_engctx_fini
+#define _nouveau_vp_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_vp_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_vp {
+ struct nouveau_engine base;
+};
+
+#define nouveau_vp_create(p,e,c,d) \
+ nouveau_engine_create((p), (e), (c), true, "PVP", "vp", (d))
+#define nouveau_vp_destroy(d) \
+ nouveau_engine_destroy(&(d)->base)
+#define nouveau_vp_init(d) \
+ nouveau_engine_init(&(d)->base)
+#define nouveau_vp_fini(d,s) \
+ nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_vp_dtor _nouveau_engine_dtor
+#define _nouveau_vp_init _nouveau_engine_init
+#define _nouveau_vp_fini _nouveau_engine_fini
+
extern struct nouveau_oclass nv84_vp_oclass;
-extern struct nouveau_oclass nvc0_vp_oclass;
-extern struct nouveau_oclass nve0_vp_oclass;
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h b/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h
index b79025da581e..d682fb625833 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h
@@ -23,7 +23,6 @@ struct dcb_output {
uint8_t bus;
uint8_t location;
uint8_t or;
- uint8_t link;
bool duallink_possible;
union {
struct sor_conf {
@@ -56,11 +55,36 @@ struct dcb_output {
u16 dcb_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len);
u16 dcb_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len);
-u16 dcb_outp_parse(struct nouveau_bios *, u8 idx, u8 *, u8 *,
- struct dcb_output *);
-u16 dcb_outp_match(struct nouveau_bios *, u16 type, u16 mask, u8 *, u8 *,
- struct dcb_output *);
int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec)
(struct nouveau_bios *, void *, int index, u16 entry));
+
+/* BIT 'U'/'d' table encoder subtables have hashes matching them to
+ * a particular set of encoders.
+ *
+ * This function returns true if a particular DCB entry matches.
+ */
+static inline bool
+dcb_hash_match(struct dcb_output *dcb, u32 hash)
+{
+ if ((hash & 0x000000f0) != (dcb->location << 4))
+ return false;
+ if ((hash & 0x0000000f) != dcb->type)
+ return false;
+ if (!(hash & (dcb->or << 16)))
+ return false;
+
+ switch (dcb->type) {
+ case DCB_OUTPUT_TMDS:
+ case DCB_OUTPUT_LVDS:
+ case DCB_OUTPUT_DP:
+ if (hash & 0x00c00000) {
+ if (!(hash & (dcb->sorconf.link << 22)))
+ return false;
+ }
+ default:
+ return true;
+ }
+}
+
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/disp.h b/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/disp.h
deleted file mode 100644
index c35937e2f6a4..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/disp.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef __NVBIOS_DISP_H__
-#define __NVBIOS_DISP_H__
-
-u16 nvbios_disp_table(struct nouveau_bios *,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *sub);
-
-struct nvbios_disp {
- u16 data;
-};
-
-u16 nvbios_disp_entry(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr__, u8 *sub);
-u16 nvbios_disp_parse(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr__, u8 *sub,
- struct nvbios_disp *);
-
-struct nvbios_outp {
- u16 type;
- u16 mask;
- u16 script[3];
-};
-
-u16 nvbios_outp_entry(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_outp_parse(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *);
-u16 nvbios_outp_match(struct nouveau_bios *, u16 type, u16 mask,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *);
-
-
-struct nvbios_ocfg {
- u16 match;
- u16 clkcmp[2];
-};
-
-u16 nvbios_ocfg_entry(struct nouveau_bios *, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_ocfg_parse(struct nouveau_bios *, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ocfg *);
-u16 nvbios_ocfg_match(struct nouveau_bios *, u16 outp, u16 type,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ocfg *);
-u16 nvbios_oclk_match(struct nouveau_bios *, u16 cmp, u32 khz);
-
-#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h b/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
index 6e54218b55fc..73b5e5d3e75a 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
@@ -1,34 +1,8 @@
#ifndef __NVBIOS_DP_H__
#define __NVBIOS_DP_H__
-struct nvbios_dpout {
- u16 type;
- u16 mask;
- u8 flags;
- u32 script[5];
- u32 lnkcmp;
-};
-
-u16 nvbios_dpout_parse(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpout *);
-u16 nvbios_dpout_match(struct nouveau_bios *, u16 type, u16 mask,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpout *);
-
-struct nvbios_dpcfg {
- u8 drv;
- u8 pre;
- u8 unk;
-};
-
-u16
-nvbios_dpcfg_parse(struct nouveau_bios *, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpcfg *);
-u16
-nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 un, u8 vs, u8 pe,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpcfg *);
+u16 dp_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 dp_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len);
+u16 dp_outp_match(struct nouveau_bios *, struct dcb_output *, u8 *ver, u8 *len);
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/trunk/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
index da470e6851b1..5c1b5e1904f9 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
+++ b/trunk/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
@@ -69,11 +69,8 @@ struct nouveau_fb {
} type;
u64 stolen;
u64 size;
-
int ranks;
- int parts;
- int (*init)(struct nouveau_fb *);
int (*get)(struct nouveau_fb *, u64 size, u32 align,
u32 size_nc, u32 type, struct nouveau_mem **);
void (*put)(struct nouveau_fb *, struct nouveau_mem **);
@@ -87,8 +84,6 @@ struct nouveau_fb {
int regions;
void (*init)(struct nouveau_fb *, int i, u32 addr, u32 size,
u32 pitch, u32 flags, struct nouveau_fb_tile *);
- void (*comp)(struct nouveau_fb *, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *);
void (*fini)(struct nouveau_fb *, int i,
struct nouveau_fb_tile *);
void (*prog)(struct nouveau_fb *, int i,
@@ -104,7 +99,7 @@ nouveau_fb(void *obj)
#define nouveau_fb_create(p,e,c,d) \
nouveau_subdev_create((p), (e), (c), 0, "PFB", "fb", (d))
-int nouveau_fb_preinit(struct nouveau_fb *);
+int nouveau_fb_created(struct nouveau_fb *);
void nouveau_fb_destroy(struct nouveau_fb *);
int nouveau_fb_init(struct nouveau_fb *);
#define nouveau_fb_fini(p,s) \
@@ -116,19 +111,9 @@ int _nouveau_fb_init(struct nouveau_object *);
extern struct nouveau_oclass nv04_fb_oclass;
extern struct nouveau_oclass nv10_fb_oclass;
-extern struct nouveau_oclass nv1a_fb_oclass;
extern struct nouveau_oclass nv20_fb_oclass;
-extern struct nouveau_oclass nv25_fb_oclass;
extern struct nouveau_oclass nv30_fb_oclass;
-extern struct nouveau_oclass nv35_fb_oclass;
-extern struct nouveau_oclass nv36_fb_oclass;
extern struct nouveau_oclass nv40_fb_oclass;
-extern struct nouveau_oclass nv41_fb_oclass;
-extern struct nouveau_oclass nv44_fb_oclass;
-extern struct nouveau_oclass nv46_fb_oclass;
-extern struct nouveau_oclass nv47_fb_oclass;
-extern struct nouveau_oclass nv49_fb_oclass;
-extern struct nouveau_oclass nv4e_fb_oclass;
extern struct nouveau_oclass nv50_fb_oclass;
extern struct nouveau_oclass nvc0_fb_oclass;
@@ -137,35 +122,13 @@ int nouveau_fb_bios_memtype(struct nouveau_bios *);
bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
-void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-int nv20_fb_vram_init(struct nouveau_fb *);
-void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int nv30_fb_init(struct nouveau_object *);
void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
u32 pitch, u32 flags, struct nouveau_fb_tile *);
-
-void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *);
-
-int nv41_fb_vram_init(struct nouveau_fb *);
-int nv41_fb_init(struct nouveau_object *);
-void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int nv44_fb_vram_init(struct nouveau_fb *);
-int nv44_fb_init(struct nouveau_object *);
-void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
+void nv30_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
void nv50_fb_vram_del(struct nouveau_fb *, struct nouveau_mem **);
+void nv50_fb_trap(struct nouveau_fb *, int display);
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/bar/base.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/bar/base.c
index d70ba342aa2e..cd01c533007a 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/bar/base.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/bar/base.c
@@ -65,14 +65,14 @@ nouveau_barobj_dtor(struct nouveau_object *object)
}
static u32
-nouveau_barobj_rd32(struct nouveau_object *object, u64 addr)
+nouveau_barobj_rd32(struct nouveau_object *object, u32 addr)
{
struct nouveau_barobj *barobj = (void *)object;
return ioread32_native(barobj->iomem + addr);
}
static void
-nouveau_barobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
+nouveau_barobj_wr32(struct nouveau_object *object, u32 addr, u32 data)
{
struct nouveau_barobj *barobj = (void *)object;
iowrite32_native(data, barobj->iomem + addr);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
index dd111947eb86..70ca7d5a1aa1 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
@@ -63,7 +63,7 @@ nouveau_bios_shadow_of(struct nouveau_bios *bios)
struct pci_dev *pdev = nv_device(bios)->pdev;
struct device_node *dn;
const u32 *data;
- int size;
+ int size, i;
dn = pci_device_to_OF_node(pdev);
if (!dn) {
@@ -210,19 +210,11 @@ nouveau_bios_shadow_acpi(struct nouveau_bios *bios)
return;
bios->data = kmalloc(bios->size, GFP_KERNEL);
- if (bios->data) {
- /* disobey the acpi spec - much faster on at least w530 ... */
- ret = nouveau_acpi_get_bios_chunk(bios->data, 0, bios->size);
- if (ret != bios->size ||
- nvbios_checksum(bios->data, bios->size)) {
- /* ... that didn't work, ok, i'll be good now */
- for (i = 0; i < bios->size; i += cnt) {
- cnt = min((bios->size - i), (u32)4096);
- ret = nouveau_acpi_get_bios_chunk(bios->data, i, cnt);
- if (ret != cnt)
- break;
- }
- }
+ for (i = 0; bios->data && i < bios->size; i += cnt) {
+ cnt = min((bios->size - i), (u32)4096);
+ ret = nouveau_acpi_get_bios_chunk(bios->data, i, cnt);
+ if (ret != cnt)
+ break;
}
}
@@ -366,42 +358,42 @@ nouveau_bios_shadow(struct nouveau_bios *bios)
}
static u8
-nouveau_bios_rd08(struct nouveau_object *object, u64 addr)
+nouveau_bios_rd08(struct nouveau_object *object, u32 addr)
{
struct nouveau_bios *bios = (void *)object;
return bios->data[addr];
}
static u16
-nouveau_bios_rd16(struct nouveau_object *object, u64 addr)
+nouveau_bios_rd16(struct nouveau_object *object, u32 addr)
{
struct nouveau_bios *bios = (void *)object;
return get_unaligned_le16(&bios->data[addr]);
}
static u32
-nouveau_bios_rd32(struct nouveau_object *object, u64 addr)
+nouveau_bios_rd32(struct nouveau_object *object, u32 addr)
{
struct nouveau_bios *bios = (void *)object;
return get_unaligned_le32(&bios->data[addr]);
}
static void
-nouveau_bios_wr08(struct nouveau_object *object, u64 addr, u8 data)
+nouveau_bios_wr08(struct nouveau_object *object, u32 addr, u8 data)
{
struct nouveau_bios *bios = (void *)object;
bios->data[addr] = data;
}
static void
-nouveau_bios_wr16(struct nouveau_object *object, u64 addr, u16 data)
+nouveau_bios_wr16(struct nouveau_object *object, u32 addr, u16 data)
{
struct nouveau_bios *bios = (void *)object;
put_unaligned_le16(data, &bios->data[addr]);
}
static void
-nouveau_bios_wr32(struct nouveau_object *object, u64 addr, u32 data)
+nouveau_bios_wr32(struct nouveau_object *object, u32 addr, u32 data)
{
struct nouveau_bios *bios = (void *)object;
put_unaligned_le32(data, &bios->data[addr]);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
index bbd709fba0a9..7d750382a833 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
@@ -107,69 +107,6 @@ dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
return 0x0000;
}
-u16
-dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
- struct dcb_output *outp)
-{
- u16 dcb = dcb_outp(bios, idx, ver, len);
- if (dcb) {
- if (*ver >= 0x20) {
- u32 conn = nv_ro32(bios, dcb + 0x00);
- outp->or = (conn & 0x0f000000) >> 24;
- outp->location = (conn & 0x00300000) >> 20;
- outp->bus = (conn & 0x000f0000) >> 16;
- outp->connector = (conn & 0x0000f000) >> 12;
- outp->heads = (conn & 0x00000f00) >> 8;
- outp->i2c_index = (conn & 0x000000f0) >> 4;
- outp->type = (conn & 0x0000000f);
- outp->link = 0;
- } else {
- dcb = 0x0000;
- }
-
- if (*ver >= 0x40) {
- u32 conf = nv_ro32(bios, dcb + 0x04);
- switch (outp->type) {
- case DCB_OUTPUT_TMDS:
- case DCB_OUTPUT_LVDS:
- case DCB_OUTPUT_DP:
- outp->link = (conf & 0x00000030) >> 4;
- outp->sorconf.link = outp->link; /*XXX*/
- break;
- default:
- break;
- }
- }
- }
- return dcb;
-}
-
-static inline u16
-dcb_outp_hasht(struct dcb_output *outp)
-{
- return outp->type;
-}
-
-static inline u16
-dcb_outp_hashm(struct dcb_output *outp)
-{
- return (outp->heads << 8) | (outp->link << 6) | outp->or;
-}
-
-u16
-dcb_outp_match(struct nouveau_bios *bios, u16 type, u16 mask,
- u8 *ver, u8 *len, struct dcb_output *outp)
-{
- u16 dcb, idx = 0;
- while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) {
- if (dcb_outp_hasht(outp) == type) {
- if ((dcb_outp_hashm(outp) & mask) == mask)
- break;
- }
- }
- return dcb;
-}
-
int
dcb_outp_foreach(struct nouveau_bios *bios, void *data,
int (*exec)(struct nouveau_bios *, void *, int, u16))
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/disp.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/disp.c
deleted file mode 100644
index 7f16e52d9bea..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/disp.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2012 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
-#include
-
-u16
-nvbios_disp_table(struct nouveau_bios *bios,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *sub)
-{
- struct bit_entry U;
-
- if (!bit_entry(bios, 'U', &U)) {
- if (U.version == 1) {
- u16 data = nv_ro16(bios, U.offset);
- if (data) {
- *ver = nv_ro08(bios, data + 0x00);
- switch (*ver) {
- case 0x20:
- case 0x21:
- *hdr = nv_ro08(bios, data + 0x01);
- *len = nv_ro08(bios, data + 0x02);
- *cnt = nv_ro08(bios, data + 0x03);
- *sub = nv_ro08(bios, data + 0x04);
- return data;
- default:
- break;
- }
- }
- }
- }
-
- return 0x0000;
-}
-
-u16
-nvbios_disp_entry(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *len, u8 *sub)
-{
- u8 hdr, cnt;
- u16 data = nvbios_disp_table(bios, ver, &hdr, &cnt, len, sub);
- if (data && idx < cnt)
- return data + hdr + (idx * *len);
- *ver = 0x00;
- return 0x0000;
-}
-
-u16
-nvbios_disp_parse(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *len, u8 *sub,
- struct nvbios_disp *info)
-{
- u16 data = nvbios_disp_entry(bios, idx, ver, len, sub);
- if (data && *len >= 2) {
- info->data = nv_ro16(bios, data + 0);
- return data;
- }
- return 0x0000;
-}
-
-u16
-nvbios_outp_entry(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- struct nvbios_disp info;
- u16 data = nvbios_disp_parse(bios, idx, ver, len, hdr, &info);
- if (data) {
- *cnt = nv_ro08(bios, info.data + 0x05);
- *len = 0x06;
- data = info.data;
- }
- return data;
-}
-
-u16
-nvbios_outp_parse(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *info)
-{
- u16 data = nvbios_outp_entry(bios, idx, ver, hdr, cnt, len);
- if (data && *hdr >= 0x0a) {
- info->type = nv_ro16(bios, data + 0x00);
- info->mask = nv_ro32(bios, data + 0x02);
- if (*ver <= 0x20) /* match any link */
- info->mask |= 0x00c0;
- info->script[0] = nv_ro16(bios, data + 0x06);
- info->script[1] = nv_ro16(bios, data + 0x08);
- info->script[2] = 0x0000;
- if (*hdr >= 0x0c)
- info->script[2] = nv_ro16(bios, data + 0x0a);
- return data;
- }
- return 0x0000;
-}
-
-u16
-nvbios_outp_match(struct nouveau_bios *bios, u16 type, u16 mask,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *info)
-{
- u16 data, idx = 0;
- while ((data = nvbios_outp_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
- if (data && info->type == type) {
- if ((info->mask & mask) == mask)
- break;
- }
- }
- return data;
-}
-
-u16
-nvbios_ocfg_entry(struct nouveau_bios *bios, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- if (idx < *cnt)
- return outp + *hdr + (idx * *len);
- return 0x0000;
-}
-
-u16
-nvbios_ocfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ocfg *info)
-{
- u16 data = nvbios_ocfg_entry(bios, outp, idx, ver, hdr, cnt, len);
- if (data) {
- info->match = nv_ro16(bios, data + 0x00);
- info->clkcmp[0] = nv_ro16(bios, data + 0x02);
- info->clkcmp[1] = nv_ro16(bios, data + 0x04);
- }
- return data;
-}
-
-u16
-nvbios_ocfg_match(struct nouveau_bios *bios, u16 outp, u16 type,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ocfg *info)
-{
- u16 data, idx = 0;
- while ((data = nvbios_ocfg_parse(bios, outp, idx++, ver, hdr, cnt, len, info))) {
- if (info->match == type)
- break;
- }
- return data;
-}
-
-u16
-nvbios_oclk_match(struct nouveau_bios *bios, u16 cmp, u32 khz)
-{
- while (cmp) {
- if (khz / 10 >= nv_ro16(bios, cmp + 0x00))
- return nv_ro16(bios, cmp + 0x02);
- cmp += 0x04;
- }
- return 0x0000;
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
index 663853bcca82..3cbc0f3e8d5e 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
@@ -25,29 +25,23 @@
#include "subdev/bios.h"
#include "subdev/bios/bit.h"
+#include "subdev/bios/dcb.h"
#include "subdev/bios/dp.h"
-static u16
-nvbios_dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+u16
+dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{
- struct bit_entry d;
+ struct bit_entry bit_d;
- if (!bit_entry(bios, 'd', &d)) {
- if (d.version == 1 && d.length >= 2) {
- u16 data = nv_ro16(bios, d.offset);
+ if (!bit_entry(bios, 'd', &bit_d)) {
+ if (bit_d.version == 1) {
+ u16 data = nv_ro16(bios, bit_d.offset);
if (data) {
- *ver = nv_ro08(bios, data + 0x00);
- switch (*ver) {
- case 0x21:
- case 0x30:
- case 0x40:
- *hdr = nv_ro08(bios, data + 0x01);
- *len = nv_ro08(bios, data + 0x02);
- *cnt = nv_ro08(bios, data + 0x03);
- return data;
- default:
- break;
- }
+ *ver = nv_ro08(bios, data + 0);
+ *hdr = nv_ro08(bios, data + 1);
+ *len = nv_ro08(bios, data + 2);
+ *cnt = nv_ro08(bios, data + 3);
+ return data;
}
}
}
@@ -55,150 +49,28 @@ nvbios_dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
return 0x0000;
}
-static u16
-nvbios_dpout_entry(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len);
- if (data && idx < *cnt) {
- u16 outp = nv_ro16(bios, data + *hdr + idx * *len);
- switch (*ver * !!outp) {
- case 0x21:
- case 0x30:
- *hdr = nv_ro08(bios, data + 0x04);
- *len = nv_ro08(bios, data + 0x05);
- *cnt = nv_ro08(bios, outp + 0x04);
- break;
- case 0x40:
- *hdr = nv_ro08(bios, data + 0x04);
- *cnt = 0;
- *len = 0;
- break;
- default:
- break;
- }
- return outp;
- }
- *ver = 0x00;
- return 0x0000;
-}
-
u16
-nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpout *info)
+dp_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
{
- u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len);
- if (data && *ver) {
- info->type = nv_ro16(bios, data + 0x00);
- info->mask = nv_ro16(bios, data + 0x02);
- switch (*ver) {
- case 0x21:
- case 0x30:
- info->flags = nv_ro08(bios, data + 0x05);
- info->script[0] = nv_ro16(bios, data + 0x06);
- info->script[1] = nv_ro16(bios, data + 0x08);
- info->lnkcmp = nv_ro16(bios, data + 0x0a);
- info->script[2] = nv_ro16(bios, data + 0x0c);
- info->script[3] = nv_ro16(bios, data + 0x0e);
- info->script[4] = nv_ro16(bios, data + 0x10);
- break;
- case 0x40:
- info->flags = nv_ro08(bios, data + 0x04);
- info->script[0] = nv_ro16(bios, data + 0x05);
- info->script[1] = nv_ro16(bios, data + 0x07);
- info->lnkcmp = nv_ro16(bios, data + 0x09);
- info->script[2] = nv_ro16(bios, data + 0x0b);
- info->script[3] = nv_ro16(bios, data + 0x0d);
- info->script[4] = nv_ro16(bios, data + 0x0f);
- break;
- default:
- data = 0x0000;
- break;
- }
- }
- return data;
+ u8 hdr, cnt;
+ u16 table = dp_table(bios, ver, &hdr, &cnt, len);
+ if (table && idx < cnt)
+ return nv_ro16(bios, table + hdr + (idx * *len));
+ return 0xffff;
}
u16
-nvbios_dpout_match(struct nouveau_bios *bios, u16 type, u16 mask,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpout *info)
-{
- u16 data, idx = 0;
- while ((data = nvbios_dpout_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
- if (data && info->type == type) {
- if ((info->mask & mask) == mask)
- break;
- }
- }
- return data;
-}
-
-static u16
-nvbios_dpcfg_entry(struct nouveau_bios *bios, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+dp_outp_match(struct nouveau_bios *bios, struct dcb_output *outp,
+ u8 *ver, u8 *len)
{
- if (*ver >= 0x40) {
- outp = nvbios_dp_table(bios, ver, hdr, cnt, len);
- *hdr = *hdr + (*len * * cnt);
- *len = nv_ro08(bios, outp + 0x06);
- *cnt = nv_ro08(bios, outp + 0x07);
- }
-
- if (idx < *cnt)
- return outp + *hdr + (idx * *len);
-
- return 0x0000;
-}
-
-u16
-nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpcfg *info)
-{
- u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len);
- if (data) {
- switch (*ver) {
- case 0x21:
- info->drv = nv_ro08(bios, data + 0x02);
- info->pre = nv_ro08(bios, data + 0x03);
- info->unk = nv_ro08(bios, data + 0x04);
- break;
- case 0x30:
- case 0x40:
- info->drv = nv_ro08(bios, data + 0x01);
- info->pre = nv_ro08(bios, data + 0x02);
- info->unk = nv_ro08(bios, data + 0x03);
- break;
- default:
- data = 0x0000;
- break;
- }
- }
- return data;
-}
-
-u16
-nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpcfg *info)
-{
- u8 idx = 0xff;
+ u8 idx = 0;
u16 data;
-
- if (*ver >= 0x30) {
- const u8 vsoff[] = { 0, 4, 7, 9 };
- idx = (un * 10) + vsoff[vs] + pe;
- } else {
- while ((data = nvbios_dpcfg_entry(bios, outp, idx,
- ver, hdr, cnt, len))) {
- if (nv_ro08(bios, data + 0x00) == vs &&
- nv_ro08(bios, data + 0x01) == pe)
- break;
- idx++;
+ while ((data = dp_outp(bios, idx++, ver, len)) != 0xffff) {
+ if (data) {
+ u32 hash = nv_ro32(bios, data);
+ if (dcb_hash_match(outp, hash))
+ return data;
}
}
-
- return nvbios_dpcfg_parse(bios, outp, pe, ver, hdr, cnt, len, info);
+ return 0x0000;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
index c90d4aa3ae4f..4c9f1e508165 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
@@ -101,8 +101,8 @@ dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line,
}
/* DCB 2.2, fixed TVDAC GPIO data */
- if ((entry = dcb_table(bios, &ver, &hdr, &cnt, &len))) {
- if (ver >= 0x22 && ver < 0x30 && func == DCB_GPIO_TVDAC0) {
+ if ((entry = dcb_table(bios, &ver, &hdr, &cnt, &len)) && ver >= 0x22) {
+ if (func == DCB_GPIO_TVDAC0) {
u8 conf = nv_ro08(bios, entry - 5);
u8 addr = nv_ro08(bios, entry - 4);
if (conf & 0x01) {
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
index ae168bbb86d8..6be8c32f6e4c 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
@@ -743,10 +743,9 @@ static void
init_dp_condition(struct nvbios_init *init)
{
struct nouveau_bios *bios = init->bios;
- struct nvbios_dpout info;
u8 cond = nv_ro08(bios, init->offset + 1);
u8 unkn = nv_ro08(bios, init->offset + 2);
- u8 ver, hdr, cnt, len;
+ u8 ver, len;
u16 data;
trace("DP_CONDITION\t0x%02x 0x%02x\n", cond, unkn);
@@ -760,12 +759,10 @@ init_dp_condition(struct nvbios_init *init)
case 1:
case 2:
if ( init->outp &&
- (data = nvbios_dpout_match(bios, DCB_OUTPUT_DP,
- (init->outp->or << 0) |
- (init->outp->sorconf.link << 6),
- &ver, &hdr, &cnt, &len, &info)))
- {
- if (!(info.flags & cond))
+ (data = dp_outp_match(bios, init->outp, &ver, &len))) {
+ if (ver <= 0x40 && !(nv_ro08(bios, data + 5) & cond))
+ init_exec_set(init, false);
+ if (ver == 0x40 && !(nv_ro08(bios, data + 4) & cond))
init_exec_set(init, false);
break;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/base.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/base.c
index f8a7ed4166cf..ca9a4648bd8a 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/base.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/base.c
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#include
@@ -60,24 +61,19 @@ struct nouveau_devobj {
static const u64 disable_map[] = {
[NVDEV_SUBDEV_VBIOS] = NV_DEVICE_DISABLE_VBIOS,
- [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_GPIO] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_I2C] = NV_DEVICE_DISABLE_CORE,
- [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE,
- [NVDEV_SUBDEV_MXM] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_MC] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_TIMER] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_FB] = NV_DEVICE_DISABLE_CORE,
- [NVDEV_SUBDEV_LTCG] = NV_DEVICE_DISABLE_CORE,
- [NVDEV_SUBDEV_IBUS] = NV_DEVICE_DISABLE_CORE,
- [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_VM] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_BAR] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_VOLT] = NV_DEVICE_DISABLE_CORE,
+ [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_THERM] = NV_DEVICE_DISABLE_CORE,
[NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_DISABLE_CORE,
- [NVDEV_ENGINE_FIFO] = NV_DEVICE_DISABLE_FIFO,
- [NVDEV_ENGINE_SW] = NV_DEVICE_DISABLE_FIFO,
[NVDEV_ENGINE_GR] = NV_DEVICE_DISABLE_GRAPH,
[NVDEV_ENGINE_MPEG] = NV_DEVICE_DISABLE_MPEG,
[NVDEV_ENGINE_ME] = NV_DEVICE_DISABLE_ME,
@@ -88,7 +84,7 @@ static const u64 disable_map[] = {
[NVDEV_ENGINE_COPY0] = NV_DEVICE_DISABLE_COPY0,
[NVDEV_ENGINE_COPY1] = NV_DEVICE_DISABLE_COPY1,
[NVDEV_ENGINE_UNK1C1] = NV_DEVICE_DISABLE_UNK1C1,
- [NVDEV_ENGINE_VENC] = NV_DEVICE_DISABLE_VENC,
+ [NVDEV_ENGINE_FIFO] = NV_DEVICE_DISABLE_FIFO,
[NVDEV_ENGINE_DISP] = NV_DEVICE_DISABLE_DISP,
[NVDEV_SUBDEV_NR] = 0,
};
@@ -212,7 +208,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
/* determine frequency of timing crystal */
if ( device->chipset < 0x17 ||
- (device->chipset >= 0x20 && device->chipset < 0x25))
+ (device->chipset >= 0x20 && device->chipset <= 0x25))
strap &= 0x00000040;
else
strap &= 0x00400040;
@@ -360,37 +356,37 @@ nouveau_devobj_fini(struct nouveau_object *object, bool suspend)
}
static u8
-nouveau_devobj_rd08(struct nouveau_object *object, u64 addr)
+nouveau_devobj_rd08(struct nouveau_object *object, u32 addr)
{
return nv_rd08(object->engine, addr);
}
static u16
-nouveau_devobj_rd16(struct nouveau_object *object, u64 addr)
+nouveau_devobj_rd16(struct nouveau_object *object, u32 addr)
{
return nv_rd16(object->engine, addr);
}
static u32
-nouveau_devobj_rd32(struct nouveau_object *object, u64 addr)
+nouveau_devobj_rd32(struct nouveau_object *object, u32 addr)
{
return nv_rd32(object->engine, addr);
}
static void
-nouveau_devobj_wr08(struct nouveau_object *object, u64 addr, u8 data)
+nouveau_devobj_wr08(struct nouveau_object *object, u32 addr, u8 data)
{
nv_wr08(object->engine, addr, data);
}
static void
-nouveau_devobj_wr16(struct nouveau_object *object, u64 addr, u16 data)
+nouveau_devobj_wr16(struct nouveau_object *object, u32 addr, u16 data)
{
nv_wr16(object->engine, addr, data);
}
static void
-nouveau_devobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
+nouveau_devobj_wr32(struct nouveau_object *object, u32 addr, u32 data)
{
nv_wr32(object->engine, addr, data);
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c
index 9c40b0fb23f6..f09accfd0e31 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c
@@ -105,7 +105,7 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -159,7 +159,7 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
index 74f88f48e1c2..5fa58b7369b5 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
@@ -72,7 +72,7 @@ nv20_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -90,7 +90,7 @@ nv20_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -108,7 +108,7 @@ nv20_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c
index 0ac1b2c4f61d..7f4b8fe6cccc 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c
@@ -72,7 +72,7 @@ nv30_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv35_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -109,7 +109,7 @@ nv30_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv36_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -128,7 +128,7 @@ nv30_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
index 41d59689a021..42deadca0f0a 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
@@ -76,7 +76,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -96,7 +96,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -116,7 +116,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -156,7 +156,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv47_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -176,7 +176,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv49_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -196,7 +196,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv49_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -216,7 +216,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv44_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -236,7 +236,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -256,7 +256,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv44_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -276,7 +276,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -296,7 +296,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv4e_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -316,7 +316,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -336,7 +336,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -356,7 +356,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
index 6ccfd8585ba2..fec3bcc9a6fc 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
@@ -98,7 +98,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nv84_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x86:
device->cname = "G86";
@@ -123,7 +123,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nv84_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x92:
device->cname = "G92";
@@ -148,7 +148,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nv84_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x94:
device->cname = "G94";
@@ -173,7 +173,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x96:
device->cname = "G96";
@@ -198,7 +198,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x98:
device->cname = "G98";
@@ -223,7 +223,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xa0:
device->cname = "G200";
@@ -248,7 +248,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva0_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xaa:
device->cname = "MCP77/MCP78";
@@ -273,7 +273,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xac:
device->cname = "MCP79/MCP7A";
@@ -298,7 +298,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xa3:
device->cname = "GT215";
@@ -324,7 +324,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xa5:
device->cname = "GT216";
@@ -349,7 +349,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xa8:
device->cname = "GT218";
@@ -374,7 +374,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xaf:
device->cname = "MCP89";
@@ -399,7 +399,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
default:
nv_fatal(device, "unknown Tesla chipset\n");
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
index f0461685a422..6697f0f9c293 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
@@ -74,12 +74,12 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xc4:
device->cname = "GF104";
@@ -102,12 +102,12 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xc3:
device->cname = "GF106";
@@ -130,12 +130,12 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xce:
device->cname = "GF114";
@@ -158,12 +158,12 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xcf:
device->cname = "GF116";
@@ -186,12 +186,12 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xc1:
device->cname = "GF108";
@@ -214,12 +214,12 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xc8:
device->cname = "GF110";
@@ -242,12 +242,12 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xd9:
device->cname = "GF119";
@@ -266,13 +266,13 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass;
break;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
index 9b7881e76634..4a280b7ab853 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
@@ -45,9 +45,6 @@
#include
#include
#include
-#include
-#include
-#include
int
nve0_identify(struct nouveau_device *device)
@@ -70,16 +67,13 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
break;
case 0xe7:
device->cname = "GK107";
@@ -98,16 +92,13 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
break;
default:
nv_fatal(device, "unknown Kepler chipset\n");
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
index ae7249b09797..61becfa732e9 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
@@ -22,10 +22,6 @@
* Authors: Ben Skeggs
*/
-#include
-#include
-#include
-#include
#include
#include
@@ -59,12 +55,7 @@ nv50_devinit_dtor(struct nouveau_object *object)
static int
nv50_devinit_init(struct nouveau_object *object)
{
- struct nouveau_bios *bios = nouveau_bios(object);
struct nv50_devinit_priv *priv = (void *)object;
- struct nvbios_outp info;
- struct dcb_output outp;
- u8 ver = 0xff, hdr, cnt, len;
- int ret, i = 0;
if (!priv->base.post) {
if (!nv_rdvgac(priv, 0, 0x00) &&
@@ -74,30 +65,7 @@ nv50_devinit_init(struct nouveau_object *object)
}
}
- ret = nouveau_devinit_init(&priv->base);
- if (ret)
- return ret;
-
- /* if we ran the init tables, execute first script pointer for each
- * display table output entry that has a matching dcb entry.
- */
- while (priv->base.post && ver) {
- u16 data = nvbios_outp_parse(bios, i++, &ver, &hdr, &cnt, &len, &info);
- if (data && dcb_outp_match(bios, info.type, info.mask, &ver, &len, &outp)) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = info.script[0],
- .outp = &outp,
- .crtc = -1,
- .execute = 1,
- };
-
- nvbios_exec(&init);
- }
- };
-
- return 0;
+ return nouveau_devinit_init(&priv->base);
}
static int
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
index d6d16007ec1a..f0086de8af31 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
@@ -57,47 +57,27 @@ nouveau_fb_bios_memtype(struct nouveau_bios *bios)
}
int
-nouveau_fb_preinit(struct nouveau_fb *pfb)
+nouveau_fb_init(struct nouveau_fb *pfb)
{
- static const char *name[] = {
- [NV_MEM_TYPE_UNKNOWN] = "unknown",
- [NV_MEM_TYPE_STOLEN ] = "stolen system memory",
- [NV_MEM_TYPE_SGRAM ] = "SGRAM",
- [NV_MEM_TYPE_SDRAM ] = "SDRAM",
- [NV_MEM_TYPE_DDR1 ] = "DDR1",
- [NV_MEM_TYPE_DDR2 ] = "DDR2",
- [NV_MEM_TYPE_DDR3 ] = "DDR3",
- [NV_MEM_TYPE_GDDR2 ] = "GDDR2",
- [NV_MEM_TYPE_GDDR3 ] = "GDDR3",
- [NV_MEM_TYPE_GDDR4 ] = "GDDR4",
- [NV_MEM_TYPE_GDDR5 ] = "GDDR5",
- };
- int ret, tags;
-
- tags = pfb->ram.init(pfb);
- if (tags < 0 || !pfb->ram.size) {
- nv_fatal(pfb, "error detecting memory configuration!!\n");
- return (tags < 0) ? tags : -ERANGE;
- }
+ int ret, i;
- if (!nouveau_mm_initialised(&pfb->vram)) {
- ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram.size >> 12, 1);
- if (ret)
- return ret;
- }
+ ret = nouveau_subdev_init(&pfb->base);
+ if (ret)
+ return ret;
- if (!nouveau_mm_initialised(&pfb->tags) && tags) {
- ret = nouveau_mm_init(&pfb->tags, 0, ++tags, 1);
- if (ret)
- return ret;
- }
+ for (i = 0; i < pfb->tile.regions; i++)
+ pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
- nv_info(pfb, "RAM type: %s\n", name[pfb->ram.type]);
- nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram.size >> 20));
- nv_info(pfb, " ZCOMP: %d tags\n", tags);
return 0;
}
+int
+_nouveau_fb_init(struct nouveau_object *object)
+{
+ struct nouveau_fb *pfb = (void *)object;
+ return nouveau_fb_init(pfb);
+}
+
void
nouveau_fb_destroy(struct nouveau_fb *pfb)
{
@@ -105,8 +85,12 @@ nouveau_fb_destroy(struct nouveau_fb *pfb)
for (i = 0; i < pfb->tile.regions; i++)
pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
- nouveau_mm_fini(&pfb->tags);
- nouveau_mm_fini(&pfb->vram);
+
+ if (pfb->tags.block_size)
+ nouveau_mm_fini(&pfb->tags);
+
+ if (pfb->vram.block_size)
+ nouveau_mm_fini(&pfb->vram);
nouveau_subdev_destroy(&pfb->base);
}
@@ -117,24 +101,30 @@ _nouveau_fb_dtor(struct nouveau_object *object)
struct nouveau_fb *pfb = (void *)object;
nouveau_fb_destroy(pfb);
}
+
int
-nouveau_fb_init(struct nouveau_fb *pfb)
+nouveau_fb_created(struct nouveau_fb *pfb)
{
- int ret, i;
-
- ret = nouveau_subdev_init(&pfb->base);
- if (ret)
- return ret;
+ static const char *name[] = {
+ [NV_MEM_TYPE_UNKNOWN] = "unknown",
+ [NV_MEM_TYPE_STOLEN ] = "stolen system memory",
+ [NV_MEM_TYPE_SGRAM ] = "SGRAM",
+ [NV_MEM_TYPE_SDRAM ] = "SDRAM",
+ [NV_MEM_TYPE_DDR1 ] = "DDR1",
+ [NV_MEM_TYPE_DDR2 ] = "DDR2",
+ [NV_MEM_TYPE_DDR3 ] = "DDR3",
+ [NV_MEM_TYPE_GDDR2 ] = "GDDR2",
+ [NV_MEM_TYPE_GDDR3 ] = "GDDR3",
+ [NV_MEM_TYPE_GDDR4 ] = "GDDR4",
+ [NV_MEM_TYPE_GDDR5 ] = "GDDR5",
+ };
- for (i = 0; i < pfb->tile.regions; i++)
- pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
+ if (pfb->ram.size == 0) {
+ nv_fatal(pfb, "no vram detected!!\n");
+ return -ERANGE;
+ }
+ nv_info(pfb, "RAM type: %s\n", name[pfb->ram.type]);
+ nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram.size >> 20));
return 0;
}
-
-int
-_nouveau_fb_init(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = (void *)object;
- return nouveau_fb_init(pfb);
-}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
index 6e369f85361e..eb06836b69f7 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
@@ -55,37 +55,6 @@ nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
return false;
}
-static int
-nv04_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
- if (boot0 & 0x00000100) {
- pfb->ram.size = ((boot0 >> 12) & 0xf) * 2 + 2;
- pfb->ram.size *= 1024 * 1024;
- } else {
- switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
- case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
- pfb->ram.size = 32 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
- pfb->ram.size = 16 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
- pfb->ram.size = 8 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
- pfb->ram.size = 4 * 1024 * 1024;
- break;
- }
- }
-
- if ((boot0 & 0x00000038) <= 0x10)
- pfb->ram.type = NV_MEM_TYPE_SGRAM;
- else
- pfb->ram.type = NV_MEM_TYPE_SDRAM;
- return 0;
-}
-
static int
nv04_fb_init(struct nouveau_object *object)
{
@@ -110,6 +79,7 @@ nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_object **pobject)
{
struct nv04_fb_priv *priv;
+ u32 boot0;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
@@ -117,9 +87,35 @@ nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ boot0 = nv_rd32(priv, NV04_PFB_BOOT_0);
+ if (boot0 & 0x00000100) {
+ priv->base.ram.size = ((boot0 >> 12) & 0xf) * 2 + 2;
+ priv->base.ram.size *= 1024 * 1024;
+ } else {
+ switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
+ priv->base.ram.size = 32 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
+ priv->base.ram.size = 16 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
+ priv->base.ram.size = 8 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
+ priv->base.ram.size = 4 * 1024 * 1024;
+ break;
+ }
+ }
+
+ if ((boot0 & 0x00000038) <= 0x10)
+ priv->base.ram.type = NV_MEM_TYPE_SGRAM;
+ else
+ priv->base.ram.type = NV_MEM_TYPE_SDRAM;
+
+
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv04_fb_vram_init;
- return nouveau_fb_preinit(&priv->base);
+ return nouveau_fb_created(&priv->base);
}
struct nouveau_oclass
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
index edbbe26e858d..f037a422d2f4 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
@@ -30,20 +30,7 @@ struct nv10_fb_priv {
struct nouveau_fb base;
};
-static int
-nv10_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 cfg0 = nv_rd32(pfb, 0x100200);
- if (cfg0 & 0x00000001)
- pfb->ram.type = NV_MEM_TYPE_DDR1;
- else
- pfb->ram.type = NV_MEM_TYPE_SDRAM;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- return 0;
-}
-
-void
+static void
nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nouveau_fb_tile *tile)
{
@@ -52,7 +39,7 @@ nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
tile->pitch = pitch;
}
-void
+static void
nv10_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
{
tile->addr = 0;
@@ -67,7 +54,6 @@ nv10_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch);
nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr);
- nv_rd32(pfb, 0x100240 + (i * 0x10));
}
static int
@@ -75,6 +61,7 @@ nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
+ struct nouveau_device *device = nv_device(parent);
struct nv10_fb_priv *priv;
int ret;
@@ -83,13 +70,42 @@ nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ if (device->chipset == 0x1a || device->chipset == 0x1f) {
+ struct pci_dev *bridge;
+ u32 mem, mib;
+
+ bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
+ if (!bridge) {
+ nv_fatal(device, "no bridge device\n");
+ return 0;
+ }
+
+ if (device->chipset == 0x1a) {
+ pci_read_config_dword(bridge, 0x7c, &mem);
+ mib = ((mem >> 6) & 31) + 1;
+ } else {
+ pci_read_config_dword(bridge, 0x84, &mem);
+ mib = ((mem >> 4) & 127) + 1;
+ }
+
+ priv->base.ram.type = NV_MEM_TYPE_STOLEN;
+ priv->base.ram.size = mib * 1024 * 1024;
+ } else {
+ u32 cfg0 = nv_rd32(priv, 0x100200);
+ if (cfg0 & 0x00000001)
+ priv->base.ram.type = NV_MEM_TYPE_DDR1;
+ else
+ priv->base.ram.type = NV_MEM_TYPE_SDRAM;
+
+ priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
+ }
+
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv10_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv10_fb_tile_init;
priv->base.tile.fini = nv10_fb_tile_fini;
priv->base.tile.prog = nv10_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return nouveau_fb_created(&priv->base);
}
struct nouveau_oclass
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
deleted file mode 100644
index 48366841db4a..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include
-
-struct nv1a_fb_priv {
- struct nouveau_fb base;
-};
-
-static int
-nv1a_fb_vram_init(struct nouveau_fb *pfb)
-{
- struct pci_dev *bridge;
- u32 mem, mib;
-
- bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
- if (!bridge) {
- nv_fatal(pfb, "no bridge device\n");
- return -ENODEV;
- }
-
- if (nv_device(pfb)->chipset == 0x1a) {
- pci_read_config_dword(bridge, 0x7c, &mem);
- mib = ((mem >> 6) & 31) + 1;
- } else {
- pci_read_config_dword(bridge, 0x84, &mem);
- mib = ((mem >> 4) & 127) + 1;
- }
-
- pfb->ram.type = NV_MEM_TYPE_STOLEN;
- pfb->ram.size = mib * 1024 * 1024;
- return 0;
-}
-
-static int
-nv1a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv1a_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv1a_fb_vram_init;
- priv->base.tile.regions = 8;
- priv->base.tile.init = nv10_fb_tile_init;
- priv->base.tile.fini = nv10_fb_tile_fini;
- priv->base.tile.prog = nv10_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
-}
-
-struct nouveau_oclass
-nv1a_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x1a),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv1a_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = _nouveau_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
index 5d14612a2c8e..4b3578fcb7fb 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
@@ -30,54 +30,43 @@ struct nv20_fb_priv {
struct nouveau_fb base;
};
-int
-nv20_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pbus1218 = nv_rd32(pfb, 0x001218);
-
- switch (pbus1218 & 0x00000300) {
- case 0x00000000: pfb->ram.type = NV_MEM_TYPE_SDRAM; break;
- case 0x00000100: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000200: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000300: pfb->ram.type = NV_MEM_TYPE_GDDR2; break;
- }
- pfb->ram.size = (nv_rd32(pfb, 0x10020c) & 0xff000000);
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-
- return nv_rd32(pfb, 0x100320);
-}
-
-void
+static void
nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nouveau_fb_tile *tile)
{
+ struct nouveau_device *device = nv_device(pfb);
+ int bpp = (flags & 2) ? 32 : 16;
+
tile->addr = 0x00000001 | addr;
tile->limit = max(1u, addr + size) - 1;
tile->pitch = pitch;
+
+ /* Allocate some of the on-die tag memory, used to store Z
+ * compression meta-data (most likely just a bitmap determining
+ * if a given tile is compressed or not).
+ */
+ size /= 256;
if (flags & 4) {
- pfb->tile.comp(pfb, i, size, flags, tile);
+ if (!nouveau_mm_head(&pfb->tags, 1, size, size, 1, &tile->tag)) {
+ /* Enable Z compression */
+ tile->zcomp = tile->tag->offset;
+ if (device->chipset >= 0x25) {
+ if (bpp == 16)
+ tile->zcomp |= 0x00100000;
+ else
+ tile->zcomp |= 0x00200000;
+ } else {
+ tile->zcomp |= 0x80000000;
+ if (bpp != 16)
+ tile->zcomp |= 0x04000000;
+ }
+ }
+
tile->addr |= 2;
}
}
static void
-nv20_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
-{
- u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
- if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
- if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
- else tile->zcomp = 0x04000000; /* Z24S8 */
- tile->zcomp |= tile->tag->offset;
- tile->zcomp |= 0x80000000; /* enable */
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x08000000;
-#endif
- }
-}
-
-void
nv20_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
{
tile->addr = 0;
@@ -87,13 +76,12 @@ nv20_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
nouveau_mm_free(&pfb->tags, &tile->tag);
}
-void
+static void
nv20_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
{
nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch);
nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr);
- nv_rd32(pfb, 0x100240 + (i * 0x10));
nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp);
}
@@ -102,7 +90,9 @@ nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
+ struct nouveau_device *device = nv_device(parent);
struct nv20_fb_priv *priv;
+ u32 pbus1218;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
@@ -110,14 +100,28 @@ nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ pbus1218 = nv_rd32(priv, 0x001218);
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_GDDR2; break;
+ }
+ priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
+
+ if (device->chipset >= 0x25)
+ ret = nouveau_mm_init(&priv->base.tags, 0, 64 * 1024, 1);
+ else
+ ret = nouveau_mm_init(&priv->base.tags, 0, 32 * 1024, 1);
+ if (ret)
+ return ret;
+
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv20_fb_tile_init;
- priv->base.tile.comp = nv20_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return nouveau_fb_created(&priv->base);
}
struct nouveau_oclass
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
deleted file mode 100644
index 0042ace6bef9..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include
-
-struct nv25_fb_priv {
- struct nouveau_fb base;
-};
-
-static void
-nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
-{
- u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
- if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
- if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
- else tile->zcomp = 0x00200000; /* Z24S8 */
- tile->zcomp |= tile->tag->offset;
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x01000000;
-#endif
- }
-}
-
-static int
-nv25_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv25_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
- priv->base.tile.regions = 8;
- priv->base.tile.init = nv20_fb_tile_init;
- priv->base.tile.comp = nv25_fb_tile_comp;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
-}
-
-struct nouveau_oclass
-nv25_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x25),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv25_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = _nouveau_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
index a7ba0d048aec..cba67bc91390 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
@@ -34,36 +34,17 @@ void
nv30_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nouveau_fb_tile *tile)
{
- /* for performance, select alternate bank offset for zeta */
- if (!(flags & 4)) {
- tile->addr = (0 << 4);
- } else {
- if (pfb->tile.comp) /* z compression */
- pfb->tile.comp(pfb, i, size, flags, tile);
- tile->addr = (1 << 4);
- }
-
- tile->addr |= 0x00000001; /* enable */
- tile->addr |= addr;
+ tile->addr = addr | 1;
tile->limit = max(1u, addr + size) - 1;
tile->pitch = pitch;
}
-static void
-nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
+void
+nv30_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
{
- u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
- if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
- if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
- else tile->zcomp |= 0x02000000; /* Z24S8 */
- tile->zcomp |= ((tile->tag->offset ) >> 6);
- tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 12;
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x10000000;
-#endif
- }
+ tile->addr = 0;
+ tile->limit = 0;
+ tile->pitch = 0;
}
static int
@@ -91,7 +72,7 @@ calc_ref(struct nv30_fb_priv *priv, int l, int k, int i)
return x;
}
-int
+static int
nv30_fb_init(struct nouveau_object *object)
{
struct nouveau_device *device = nv_device(object);
@@ -130,6 +111,7 @@ nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_object **pobject)
{
struct nv30_fb_priv *priv;
+ u32 pbus1218;
int ret;
ret = nouveau_fb_create(parent, engine, oclass, &priv);
@@ -137,14 +119,21 @@ nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ pbus1218 = nv_rd32(priv, 0x001218);
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_GDDR2; break;
+ }
+ priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
+
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv30_fb_tile_init;
- priv->base.tile.comp = nv30_fb_tile_comp;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ priv->base.tile.fini = nv30_fb_tile_fini;
+ priv->base.tile.prog = nv10_fb_tile_prog;
+ return nouveau_fb_created(&priv->base);
}
struct nouveau_oclass
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
deleted file mode 100644
index 092f6f4f3521..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include
-
-struct nv35_fb_priv {
- struct nouveau_fb base;
-};
-
-static void
-nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
-{
- u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
- if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
- if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
- else tile->zcomp |= 0x08000000; /* Z24S8 */
- tile->zcomp |= ((tile->tag->offset ) >> 6);
- tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 13;
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x40000000;
-#endif
- }
-}
-
-static int
-nv35_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv35_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
- priv->base.tile.regions = 8;
- priv->base.tile.init = nv30_fb_tile_init;
- priv->base.tile.comp = nv35_fb_tile_comp;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
-}
-
-struct nouveau_oclass
-nv35_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x35),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv35_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv30_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
deleted file mode 100644
index 797ab3b821b9..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include
-
-struct nv36_fb_priv {
- struct nouveau_fb base;
-};
-
-static void
-nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
-{
- u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
- if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
- if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
- else tile->zcomp |= 0x20000000; /* Z24S8 */
- tile->zcomp |= ((tile->tag->offset ) >> 6);
- tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 14;
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x80000000;
-#endif
- }
-}
-
-static int
-nv36_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv36_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
- priv->base.tile.regions = 8;
- priv->base.tile.init = nv30_fb_tile_init;
- priv->base.tile.comp = nv36_fb_tile_comp;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
-}
-
-struct nouveau_oclass
-nv36_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x36),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv36_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv30_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
index 65e131b90f37..347a496fcad8 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
@@ -30,37 +30,34 @@ struct nv40_fb_priv {
struct nouveau_fb base;
};
-static int
-nv40_fb_vram_init(struct nouveau_fb *pfb)
+static inline int
+nv44_graph_class(struct nouveau_device *device)
{
- u32 pbus1218 = nv_rd32(pfb, 0x001218);
- switch (pbus1218 & 0x00000300) {
- case 0x00000000: pfb->ram.type = NV_MEM_TYPE_SDRAM; break;
- case 0x00000100: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000200: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000300: pfb->ram.type = NV_MEM_TYPE_DDR2; break;
- }
+ if ((device->chipset & 0xf0) == 0x60)
+ return 1;
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- return nv_rd32(pfb, 0x100320);
+ return !(0x0baf & (1 << (device->chipset & 0x0f)));
}
-void
-nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
+static void
+nv40_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
{
- u32 tiles = DIV_ROUND_UP(size, 0x80);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x100);
- if ( (flags & 2) &&
- !nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
- tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */
- tile->zcomp |= ((tile->tag->offset ) >> 8);
- tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13;
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x40000000;
-#endif
- }
+ nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
+ nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
+ nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
+}
+
+static void
+nv40_fb_init_gart(struct nv40_fb_priv *priv)
+{
+ nv_wr32(priv, 0x100800, 0x00000001);
+}
+
+static void
+nv44_fb_init_gart(struct nv40_fb_priv *priv)
+{
+ nv_wr32(priv, 0x100850, 0x80000000);
+ nv_wr32(priv, 0x100800, 0x00000001);
}
static int
@@ -73,7 +70,19 @@ nv40_fb_init(struct nouveau_object *object)
if (ret)
return ret;
- nv_mask(priv, 0x10033c, 0x00008000, 0x00000000);
+ switch (nv_device(priv)->chipset) {
+ case 0x40:
+ case 0x45:
+ nv_mask(priv, 0x10033c, 0x00008000, 0x00000000);
+ break;
+ default:
+ if (nv44_graph_class(nv_device(priv)))
+ nv44_fb_init_gart(priv);
+ else
+ nv40_fb_init_gart(priv);
+ break;
+ }
+
return 0;
}
@@ -82,6 +91,7 @@ nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
+ struct nouveau_device *device = nv_device(parent);
struct nv40_fb_priv *priv;
int ret;
@@ -90,14 +100,69 @@ nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ /* 0x001218 is actually present on a few other NV4X I looked at,
+ * and even contains sane values matching 0x100474. From looking
+ * at various vbios images however, this isn't the case everywhere.
+ * So, I chose to use the same regs I've seen NVIDIA reading around
+ * the memory detection, hopefully that'll get us the right numbers
+ */
+ if (device->chipset == 0x40) {
+ u32 pbus1218 = nv_rd32(priv, 0x001218);
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_DDR2; break;
+ }
+ } else
+ if (device->chipset == 0x49 || device->chipset == 0x4b) {
+ u32 pfb914 = nv_rd32(priv, 0x100914);
+ switch (pfb914 & 0x00000003) {
+ case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000001: priv->base.ram.type = NV_MEM_TYPE_DDR2; break;
+ case 0x00000002: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000003: break;
+ }
+ } else
+ if (device->chipset != 0x4e) {
+ u32 pfb474 = nv_rd32(priv, 0x100474);
+ if (pfb474 & 0x00000004)
+ priv->base.ram.type = NV_MEM_TYPE_GDDR3;
+ if (pfb474 & 0x00000002)
+ priv->base.ram.type = NV_MEM_TYPE_DDR2;
+ if (pfb474 & 0x00000001)
+ priv->base.ram.type = NV_MEM_TYPE_DDR1;
+ } else {
+ priv->base.ram.type = NV_MEM_TYPE_STOLEN;
+ }
+
+ priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
+
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv40_fb_vram_init;
- priv->base.tile.regions = 8;
+ switch (device->chipset) {
+ case 0x40:
+ case 0x45:
+ priv->base.tile.regions = 8;
+ break;
+ case 0x46:
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ case 0x4c:
+ priv->base.tile.regions = 15;
+ break;
+ default:
+ priv->base.tile.regions = 12;
+ break;
+ }
priv->base.tile.init = nv30_fb_tile_init;
- priv->base.tile.comp = nv40_fb_tile_comp;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ priv->base.tile.fini = nv30_fb_tile_fini;
+ if (device->chipset == 0x40)
+ priv->base.tile.prog = nv10_fb_tile_prog;
+ else
+ priv->base.tile.prog = nv40_fb_tile_prog;
+
+ return nouveau_fb_created(&priv->base);
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
deleted file mode 100644
index e9e5a08c41a1..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include
-
-struct nv41_fb_priv {
- struct nouveau_fb base;
-};
-
-int
-nv41_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pfb474 = nv_rd32(pfb, 0x100474);
- if (pfb474 & 0x00000004)
- pfb->ram.type = NV_MEM_TYPE_GDDR3;
- if (pfb474 & 0x00000002)
- pfb->ram.type = NV_MEM_TYPE_DDR2;
- if (pfb474 & 0x00000001)
- pfb->ram.type = NV_MEM_TYPE_DDR1;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- return nv_rd32(pfb, 0x100320);
-}
-
-void
-nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
- nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
- nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
- nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
- nv_rd32(pfb, 0x100600 + (i * 0x10));
- nv_wr32(pfb, 0x100700 + (i * 0x04), tile->zcomp);
-}
-
-int
-nv41_fb_init(struct nouveau_object *object)
-{
- struct nv41_fb_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x100800, 0x00000001);
- return 0;
-}
-
-static int
-nv41_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv41_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv41_fb_vram_init;
- priv->base.tile.regions = 12;
- priv->base.tile.init = nv30_fb_tile_init;
- priv->base.tile.comp = nv40_fb_tile_comp;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv41_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
-}
-
-
-struct nouveau_oclass
-nv41_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x41),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv41_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv41_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
deleted file mode 100644
index ae89b5006f7a..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include
-
-struct nv44_fb_priv {
- struct nouveau_fb base;
-};
-
-int
-nv44_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pfb474 = nv_rd32(pfb, 0x100474);
- if (pfb474 & 0x00000004)
- pfb->ram.type = NV_MEM_TYPE_GDDR3;
- if (pfb474 & 0x00000002)
- pfb->ram.type = NV_MEM_TYPE_DDR2;
- if (pfb474 & 0x00000001)
- pfb->ram.type = NV_MEM_TYPE_DDR1;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- return 0;
-}
-
-static void
-nv44_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
- u32 flags, struct nouveau_fb_tile *tile)
-{
- tile->addr = 0x00000001; /* mode = vram */
- tile->addr |= addr;
- tile->limit = max(1u, addr + size) - 1;
- tile->pitch = pitch;
-}
-
-void
-nv44_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
- nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
- nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
- nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
- nv_rd32(pfb, 0x100600 + (i * 0x10));
-}
-
-int
-nv44_fb_init(struct nouveau_object *object)
-{
- struct nv44_fb_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x100850, 0x80000000);
- nv_wr32(priv, 0x100800, 0x00000001);
- return 0;
-}
-
-static int
-nv44_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv44_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv44_fb_vram_init;
- priv->base.tile.regions = 12;
- priv->base.tile.init = nv44_fb_tile_init;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv44_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
-}
-
-
-struct nouveau_oclass
-nv44_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x44),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv44_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv44_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
deleted file mode 100644
index 589b93ea2994..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include
-
-struct nv46_fb_priv {
- struct nouveau_fb base;
-};
-
-void
-nv46_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
- u32 flags, struct nouveau_fb_tile *tile)
-{
- /* for performance, select alternate bank offset for zeta */
- if (!(flags & 4)) tile->addr = (0 << 3);
- else tile->addr = (1 << 3);
-
- tile->addr |= 0x00000001; /* mode = vram */
- tile->addr |= addr;
- tile->limit = max(1u, addr + size) - 1;
- tile->pitch = pitch;
-}
-
-static int
-nv46_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv46_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv44_fb_vram_init;
- priv->base.tile.regions = 15;
- priv->base.tile.init = nv46_fb_tile_init;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv44_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
-}
-
-
-struct nouveau_oclass
-nv46_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x46),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv46_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv44_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
deleted file mode 100644
index 818bba35b368..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include
-
-struct nv47_fb_priv {
- struct nouveau_fb base;
-};
-
-static int
-nv47_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv47_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv41_fb_vram_init;
- priv->base.tile.regions = 15;
- priv->base.tile.init = nv30_fb_tile_init;
- priv->base.tile.comp = nv40_fb_tile_comp;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv41_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
-}
-
-
-struct nouveau_oclass
-nv47_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x47),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv47_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv41_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
deleted file mode 100644
index 84a31af16ab4..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include
-
-struct nv49_fb_priv {
- struct nouveau_fb base;
-};
-
-static int
-nv49_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pfb914 = nv_rd32(pfb, 0x100914);
-
- switch (pfb914 & 0x00000003) {
- case 0x00000000: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000001: pfb->ram.type = NV_MEM_TYPE_DDR2; break;
- case 0x00000002: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000003: break;
- }
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- return nv_rd32(pfb, 0x100320);
-}
-
-static int
-nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv49_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv49_fb_vram_init;
- priv->base.tile.regions = 15;
- priv->base.tile.init = nv30_fb_tile_init;
- priv->base.tile.comp = nv40_fb_tile_comp;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv41_fb_tile_prog;
-
- return nouveau_fb_preinit(&priv->base);
-}
-
-
-struct nouveau_oclass
-nv49_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x49),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv49_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv41_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
deleted file mode 100644
index 797fd558170b..000000000000
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include
-
-struct nv4e_fb_priv {
- struct nouveau_fb base;
-};
-
-static int
-nv4e_fb_vram_init(struct nouveau_fb *pfb)
-{
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.type = NV_MEM_TYPE_STOLEN;
- return 0;
-}
-
-static int
-nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv4e_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv4e_fb_vram_init;
- priv->base.tile.regions = 12;
- priv->base.tile.init = nv46_fb_tile_init;
- priv->base.tile.fini = nv20_fb_tile_fini;
- priv->base.tile.prog = nv44_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
-}
-
-struct nouveau_oclass
-nv4e_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x4e),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv4e_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv44_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
index 487cb8c6c204..5f570806143a 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
@@ -51,101 +51,6 @@ nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype)
return types[(memtype & 0xff00) >> 8] != 0;
}
-static u32
-nv50_fb_vram_rblock(struct nouveau_fb *pfb)
-{
- int i, parts, colbits, rowbitsa, rowbitsb, banks;
- u64 rowsize, predicted;
- u32 r0, r4, rt, ru, rblock_size;
-
- r0 = nv_rd32(pfb, 0x100200);
- r4 = nv_rd32(pfb, 0x100204);
- rt = nv_rd32(pfb, 0x100250);
- ru = nv_rd32(pfb, 0x001540);
- nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
-
- for (i = 0, parts = 0; i < 8; i++) {
- if (ru & (0x00010000 << i))
- parts++;
- }
-
- colbits = (r4 & 0x0000f000) >> 12;
- rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
- rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
- banks = 1 << (((r4 & 0x03000000) >> 24) + 2);
-
- rowsize = parts * banks * (1 << colbits) * 8;
- predicted = rowsize << rowbitsa;
- if (r0 & 0x00000004)
- predicted += rowsize << rowbitsb;
-
- if (predicted != pfb->ram.size) {
- nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
- (u32)(pfb->ram.size >> 20));
- }
-
- rblock_size = rowsize;
- if (rt & 1)
- rblock_size *= 3;
-
- nv_debug(pfb, "rblock %d bytes\n", rblock_size);
- return rblock_size;
-}
-
-static int
-nv50_fb_vram_init(struct nouveau_fb *pfb)
-{
- struct nouveau_device *device = nv_device(pfb);
- struct nouveau_bios *bios = nouveau_bios(device);
- const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
- const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
- u32 size;
- int ret;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c);
- pfb->ram.size = (pfb->ram.size & 0xffffff00) |
- ((pfb->ram.size & 0x000000ff) << 32);
-
- size = (pfb->ram.size >> 12) - rsvd_head - rsvd_tail;
- switch (device->chipset) {
- case 0xaa:
- case 0xac:
- case 0xaf: /* IGPs, no reordering, no real VRAM */
- ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1);
- if (ret)
- return ret;
-
- pfb->ram.type = NV_MEM_TYPE_STOLEN;
- pfb->ram.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
- break;
- default:
- switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
- case 0: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 1:
- if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
- pfb->ram.type = NV_MEM_TYPE_DDR3;
- else
- pfb->ram.type = NV_MEM_TYPE_DDR2;
- break;
- case 2: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 3: pfb->ram.type = NV_MEM_TYPE_GDDR4; break;
- case 4: pfb->ram.type = NV_MEM_TYPE_GDDR5; break;
- default:
- break;
- }
-
- ret = nouveau_mm_init(&pfb->vram, rsvd_head, size,
- nv50_fb_vram_rblock(pfb) >> 12);
- if (ret)
- return ret;
-
- pfb->ram.ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
- break;
- }
-
- return nv_rd32(pfb, 0x100320);
-}
-
static int
nv50_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
u32 memtype, struct nouveau_mem **pmem)
@@ -235,6 +140,195 @@ nv50_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
kfree(mem);
}
+static u32
+nv50_vram_rblock(struct nv50_fb_priv *priv)
+{
+ int i, parts, colbits, rowbitsa, rowbitsb, banks;
+ u64 rowsize, predicted;
+ u32 r0, r4, rt, ru, rblock_size;
+
+ r0 = nv_rd32(priv, 0x100200);
+ r4 = nv_rd32(priv, 0x100204);
+ rt = nv_rd32(priv, 0x100250);
+ ru = nv_rd32(priv, 0x001540);
+ nv_debug(priv, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
+
+ for (i = 0, parts = 0; i < 8; i++) {
+ if (ru & (0x00010000 << i))
+ parts++;
+ }
+
+ colbits = (r4 & 0x0000f000) >> 12;
+ rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
+ rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
+ banks = 1 << (((r4 & 0x03000000) >> 24) + 2);
+
+ rowsize = parts * banks * (1 << colbits) * 8;
+ predicted = rowsize << rowbitsa;
+ if (r0 & 0x00000004)
+ predicted += rowsize << rowbitsb;
+
+ if (predicted != priv->base.ram.size) {
+ nv_warn(priv, "memory controller reports %d MiB VRAM\n",
+ (u32)(priv->base.ram.size >> 20));
+ }
+
+ rblock_size = rowsize;
+ if (rt & 1)
+ rblock_size *= 3;
+
+ nv_debug(priv, "rblock %d bytes\n", rblock_size);
+ return rblock_size;
+}
+
+static int
+nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_device *device = nv_device(parent);
+ struct nouveau_bios *bios = nouveau_bios(device);
+ const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+ struct nv50_fb_priv *priv;
+ u32 tags;
+ int ret;
+
+ ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ switch (nv_rd32(priv, 0x100714) & 0x00000007) {
+ case 0: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
+ case 1:
+ if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
+ priv->base.ram.type = NV_MEM_TYPE_DDR3;
+ else
+ priv->base.ram.type = NV_MEM_TYPE_DDR2;
+ break;
+ case 2: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
+ case 3: priv->base.ram.type = NV_MEM_TYPE_GDDR4; break;
+ case 4: priv->base.ram.type = NV_MEM_TYPE_GDDR5; break;
+ default:
+ break;
+ }
+
+ priv->base.ram.size = nv_rd32(priv, 0x10020c);
+ priv->base.ram.size = (priv->base.ram.size & 0xffffff00) |
+ ((priv->base.ram.size & 0x000000ff) << 32);
+
+ tags = nv_rd32(priv, 0x100320);
+ ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1);
+ if (ret)
+ return ret;
+
+ nv_debug(priv, "%d compression tags\n", tags);
+
+ size = (priv->base.ram.size >> 12) - rsvd_head - rsvd_tail;
+ switch (device->chipset) {
+ case 0xaa:
+ case 0xac:
+ case 0xaf: /* IGPs, no reordering, no real VRAM */
+ ret = nouveau_mm_init(&priv->base.vram, rsvd_head, size, 1);
+ if (ret)
+ return ret;
+
+ priv->base.ram.stolen = (u64)nv_rd32(priv, 0x100e10) << 12;
+ priv->base.ram.type = NV_MEM_TYPE_STOLEN;
+ break;
+ default:
+ ret = nouveau_mm_init(&priv->base.vram, rsvd_head, size,
+ nv50_vram_rblock(priv) >> 12);
+ if (ret)
+ return ret;
+
+ priv->base.ram.ranks = (nv_rd32(priv, 0x100200) & 0x4) ? 2 : 1;
+ break;
+ }
+
+ priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (priv->r100c08_page) {
+ priv->r100c08 = pci_map_page(device->pdev, priv->r100c08_page,
+ 0, PAGE_SIZE,
+ PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(device->pdev, priv->r100c08))
+ nv_warn(priv, "failed 0x100c08 page map\n");
+ } else {
+ nv_warn(priv, "failed 0x100c08 page alloc\n");
+ }
+
+ priv->base.memtype_valid = nv50_fb_memtype_valid;
+ priv->base.ram.get = nv50_fb_vram_new;
+ priv->base.ram.put = nv50_fb_vram_del;
+ return nouveau_fb_created(&priv->base);
+}
+
+static void
+nv50_fb_dtor(struct nouveau_object *object)
+{
+ struct nouveau_device *device = nv_device(object);
+ struct nv50_fb_priv *priv = (void *)object;
+
+ if (priv->r100c08_page) {
+ pci_unmap_page(device->pdev, priv->r100c08, PAGE_SIZE,
+ PCI_DMA_BIDIRECTIONAL);
+ __free_page(priv->r100c08_page);
+ }
+
+ nouveau_fb_destroy(&priv->base);
+}
+
+static int
+nv50_fb_init(struct nouveau_object *object)
+{
+ struct nouveau_device *device = nv_device(object);
+ struct nv50_fb_priv *priv = (void *)object;
+ int ret;
+
+ ret = nouveau_fb_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* Not a clue what this is exactly. Without pointing it at a
+ * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
+ * cause IOMMU "read from address 0" errors (rh#561267)
+ */
+ nv_wr32(priv, 0x100c08, priv->r100c08 >> 8);
+
+ /* This is needed to get meaningful information from 100c90
+ * on traps. No idea what these values mean exactly. */
+ switch (device->chipset) {
+ case 0x50:
+ nv_wr32(priv, 0x100c90, 0x000707ff);
+ break;
+ case 0xa3:
+ case 0xa5:
+ case 0xa8:
+ nv_wr32(priv, 0x100c90, 0x000d0fff);
+ break;
+ case 0xaf:
+ nv_wr32(priv, 0x100c90, 0x089d1fff);
+ break;
+ default:
+ nv_wr32(priv, 0x100c90, 0x001d07ff);
+ break;
+ }
+
+ return 0;
+}
+
+struct nouveau_oclass
+nv50_fb_oclass = {
+ .handle = NV_SUBDEV(FB, 0x50),
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv50_fb_ctor,
+ .dtor = nv50_fb_dtor,
+ .init = nv50_fb_init,
+ .fini = _nouveau_fb_fini,
+ },
+};
+
static const struct nouveau_enum vm_dispatch_subclients[] = {
{ 0x00000000, "GRCTX", NULL },
{ 0x00000001, "NOTIFY", NULL },
@@ -330,11 +424,11 @@ static const struct nouveau_enum vm_fault[] = {
{}
};
-static void
-nv50_fb_intr(struct nouveau_subdev *subdev)
+void
+nv50_fb_trap(struct nouveau_fb *pfb, int display)
{
- struct nouveau_device *device = nv_device(subdev);
- struct nv50_fb_priv *priv = (void *)subdev;
+ struct nouveau_device *device = nv_device(pfb);
+ struct nv50_fb_priv *priv = (void *)pfb;
const struct nouveau_enum *en, *cl;
u32 trap[6], idx, chan;
u8 st0, st1, st2, st3;
@@ -351,6 +445,9 @@ nv50_fb_intr(struct nouveau_subdev *subdev)
}
nv_wr32(priv, 0x100c90, idx | 0x80000000);
+ if (!display)
+ return;
+
/* decode status bits into something more useful */
if (device->chipset < 0xa3 ||
device->chipset == 0xaa || device->chipset == 0xac) {
@@ -397,101 +494,3 @@ nv50_fb_intr(struct nouveau_subdev *subdev)
else
printk("0x%08x\n", st1);
}
-
-static int
-nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nv50_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (priv->r100c08_page) {
- priv->r100c08 = pci_map_page(device->pdev, priv->r100c08_page,
- 0, PAGE_SIZE,
- PCI_DMA_BIDIRECTIONAL);
- if (pci_dma_mapping_error(device->pdev, priv->r100c08))
- nv_warn(priv, "failed 0x100c08 page map\n");
- } else {
- nv_warn(priv, "failed 0x100c08 page alloc\n");
- }
-
- priv->base.memtype_valid = nv50_fb_memtype_valid;
- priv->base.ram.init = nv50_fb_vram_init;
- priv->base.ram.get = nv50_fb_vram_new;
- priv->base.ram.put = nv50_fb_vram_del;
- nv_subdev(priv)->intr = nv50_fb_intr;
- return nouveau_fb_preinit(&priv->base);
-}
-
-static void
-nv50_fb_dtor(struct nouveau_object *object)
-{
- struct nouveau_device *device = nv_device(object);
- struct nv50_fb_priv *priv = (void *)object;
-
- if (priv->r100c08_page) {
- pci_unmap_page(device->pdev, priv->r100c08, PAGE_SIZE,
- PCI_DMA_BIDIRECTIONAL);
- __free_page(priv->r100c08_page);
- }
-
- nouveau_fb_destroy(&priv->base);
-}
-
-static int
-nv50_fb_init(struct nouveau_object *object)
-{
- struct nouveau_device *device = nv_device(object);
- struct nv50_fb_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- /* Not a clue what this is exactly. Without pointing it at a
- * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
- * cause IOMMU "read from address 0" errors (rh#561267)
- */
- nv_wr32(priv, 0x100c08, priv->r100c08 >> 8);
-
- /* This is needed to get meaningful information from 100c90
- * on traps. No idea what these values mean exactly. */
- switch (device->chipset) {
- case 0x50:
- nv_wr32(priv, 0x100c90, 0x000707ff);
- break;
- case 0xa3:
- case 0xa5:
- case 0xa8:
- nv_wr32(priv, 0x100c90, 0x000d0fff);
- break;
- case 0xaf:
- nv_wr32(priv, 0x100c90, 0x089d1fff);
- break;
- default:
- nv_wr32(priv, 0x100c90, 0x001d07ff);
- break;
- }
-
- return 0;
-}
-
-struct nouveau_oclass
-nv50_fb_oclass = {
- .handle = NV_SUBDEV(FB, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_fb_ctor,
- .dtor = nv50_fb_dtor,
- .init = nv50_fb_init,
- .fini = _nouveau_fb_fini,
- },
-};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
index 306bdf121452..9f59f2bf0079 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
@@ -61,65 +61,6 @@ nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
return likely((types[memtype] == 1));
}
-static int
-nvc0_fb_vram_init(struct nouveau_fb *pfb)
-{
- struct nouveau_bios *bios = nouveau_bios(pfb);
- const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
- const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
- u32 parts = nv_rd32(pfb, 0x022438);
- u32 pmask = nv_rd32(pfb, 0x022554);
- u32 bsize = nv_rd32(pfb, 0x10f20c);
- u32 offset, length;
- bool uniform = true;
- int ret, part;
-
- nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
- nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
-
- pfb->ram.type = nouveau_fb_bios_memtype(bios);
- pfb->ram.ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
-
- /* read amount of vram attached to each memory controller */
- for (part = 0; part < parts; part++) {
- if (!(pmask & (1 << part))) {
- u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
- if (psize != bsize) {
- if (psize < bsize)
- bsize = psize;
- uniform = false;
- }
-
- nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
- pfb->ram.size += (u64)psize << 20;
- }
- }
-
- /* if all controllers have the same amount attached, there's no holes */
- if (uniform) {
- offset = rsvd_head;
- length = (pfb->ram.size >> 12) - rsvd_head - rsvd_tail;
- return nouveau_mm_init(&pfb->vram, offset, length, 1);
- }
-
- /* otherwise, address lowest common amount from 0GiB */
- ret = nouveau_mm_init(&pfb->vram, rsvd_head, (bsize << 8) * parts, 1);
- if (ret)
- return ret;
-
- /* and the rest starting from (8GiB + common_size) */
- offset = (0x0200000000ULL >> 12) + (bsize << 8);
- length = (pfb->ram.size >> 12) - (bsize << 8) - rsvd_tail;
-
- ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
- if (ret) {
- nouveau_mm_fini(&pfb->vram);
- return ret;
- }
-
- return 0;
-}
-
static int
nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
u32 memtype, struct nouveau_mem **pmem)
@@ -197,6 +138,66 @@ nvc0_fb_dtor(struct nouveau_object *object)
nouveau_fb_destroy(&priv->base);
}
+static int
+nvc0_vram_detect(struct nvc0_fb_priv *priv)
+{
+ struct nouveau_bios *bios = nouveau_bios(priv);
+ struct nouveau_fb *pfb = &priv->base;
+ const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+ u32 parts = nv_rd32(priv, 0x022438);
+ u32 pmask = nv_rd32(priv, 0x022554);
+ u32 bsize = nv_rd32(priv, 0x10f20c);
+ u32 offset, length;
+ bool uniform = true;
+ int ret, part;
+
+ nv_debug(priv, "0x100800: 0x%08x\n", nv_rd32(priv, 0x100800));
+ nv_debug(priv, "parts 0x%08x mask 0x%08x\n", parts, pmask);
+
+ priv->base.ram.type = nouveau_fb_bios_memtype(bios);
+ priv->base.ram.ranks = (nv_rd32(priv, 0x10f200) & 0x00000004) ? 2 : 1;
+
+ /* read amount of vram attached to each memory controller */
+ for (part = 0; part < parts; part++) {
+ if (!(pmask & (1 << part))) {
+ u32 psize = nv_rd32(priv, 0x11020c + (part * 0x1000));
+ if (psize != bsize) {
+ if (psize < bsize)
+ bsize = psize;
+ uniform = false;
+ }
+
+ nv_debug(priv, "%d: mem_amount 0x%08x\n", part, psize);
+ priv->base.ram.size += (u64)psize << 20;
+ }
+ }
+
+ /* if all controllers have the same amount attached, there's no holes */
+ if (uniform) {
+ offset = rsvd_head;
+ length = (priv->base.ram.size >> 12) - rsvd_head - rsvd_tail;
+ return nouveau_mm_init(&pfb->vram, offset, length, 1);
+ }
+
+ /* otherwise, address lowest common amount from 0GiB */
+ ret = nouveau_mm_init(&pfb->vram, rsvd_head, (bsize << 8) * parts, 1);
+ if (ret)
+ return ret;
+
+ /* and the rest starting from (8GiB + common_size) */
+ offset = (0x0200000000ULL >> 12) + (bsize << 8);
+ length = (priv->base.ram.size >> 12) - (bsize << 8) - rsvd_tail;
+
+ ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
+ if (ret) {
+ nouveau_mm_fini(&pfb->vram);
+ return ret;
+ }
+
+ return 0;
+}
+
static int
nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@@ -212,10 +213,13 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.memtype_valid = nvc0_fb_memtype_valid;
- priv->base.ram.init = nvc0_fb_vram_init;
priv->base.ram.get = nvc0_fb_vram_new;
priv->base.ram.put = nv50_fb_vram_del;
+ ret = nvc0_vram_detect(priv);
+ if (ret)
+ return ret;
+
priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!priv->r100c10_page)
return -ENOMEM;
@@ -225,7 +229,7 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (pci_dma_mapping_error(device->pdev, priv->r100c10))
return -EFAULT;
- return nouveau_fb_preinit(&priv->base);
+ return nouveau_fb_created(&priv->base);
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
index dc27e794a851..fe1ebf199ba9 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
@@ -50,7 +50,7 @@ auxch_init(struct nouveau_i2c *aux, int ch)
ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
udelay(1);
if (!timeout--) {
- AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
+ AUX_ERR("begin idle timeout 0x%08x", ctrl);
return -EBUSY;
}
} while (ctrl & 0x03010000);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
index f5bbd3834116..ba4d28b50368 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
@@ -63,14 +63,14 @@ nv04_instobj_dtor(struct nouveau_object *object)
}
static u32
-nv04_instobj_rd32(struct nouveau_object *object, u64 addr)
+nv04_instobj_rd32(struct nouveau_object *object, u32 addr)
{
struct nv04_instobj_priv *node = (void *)object;
return nv_ro32(object->engine, node->mem->offset + addr);
}
static void
-nv04_instobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
+nv04_instobj_wr32(struct nouveau_object *object, u32 addr, u32 data)
{
struct nv04_instobj_priv *node = (void *)object;
nv_wo32(object->engine, node->mem->offset + addr, data);
@@ -173,13 +173,13 @@ nv04_instmem_dtor(struct nouveau_object *object)
}
static u32
-nv04_instmem_rd32(struct nouveau_object *object, u64 addr)
+nv04_instmem_rd32(struct nouveau_object *object, u32 addr)
{
return nv_rd32(object, 0x700000 + addr);
}
static void
-nv04_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data)
+nv04_instmem_wr32(struct nouveau_object *object, u32 addr, u32 data)
{
return nv_wr32(object, 0x700000 + addr, data);
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
index da64253201ef..73c52ebd5932 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
@@ -111,14 +111,14 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
}
static u32
-nv40_instmem_rd32(struct nouveau_object *object, u64 addr)
+nv40_instmem_rd32(struct nouveau_object *object, u32 addr)
{
struct nv04_instmem_priv *priv = (void *)object;
return ioread32_native(priv->iomem + addr);
}
static void
-nv40_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data)
+nv40_instmem_wr32(struct nouveau_object *object, u32 addr, u32 data)
{
struct nv04_instmem_priv *priv = (void *)object;
iowrite32_native(data, priv->iomem + addr);
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
index cfc7e31461de..27ef0891d10b 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
@@ -76,7 +76,7 @@ nv50_instobj_dtor(struct nouveau_object *object)
}
static u32
-nv50_instobj_rd32(struct nouveau_object *object, u64 offset)
+nv50_instobj_rd32(struct nouveau_object *object, u32 offset)
{
struct nv50_instmem_priv *priv = (void *)object->engine;
struct nv50_instobj_priv *node = (void *)object;
@@ -96,7 +96,7 @@ nv50_instobj_rd32(struct nouveau_object *object, u64 offset)
}
static void
-nv50_instobj_wr32(struct nouveau_object *object, u64 offset, u32 data)
+nv50_instobj_wr32(struct nouveau_object *object, u32 offset, u32 data)
{
struct nv50_instmem_priv *priv = (void *)object->engine;
struct nv50_instobj_priv *node = (void *)object;
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
index 8379aafa6e1b..de5721cfc4c2 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
@@ -30,20 +30,20 @@ nouveau_mc_intr(struct nouveau_subdev *subdev)
struct nouveau_mc *pmc = nouveau_mc(subdev);
const struct nouveau_mc_intr *map = pmc->intr_map;
struct nouveau_subdev *unit;
- u32 stat, intr;
+ u32 stat;
- intr = stat = nv_rd32(pmc, 0x000100);
+ stat = nv_rd32(pmc, 0x000100);
while (stat && map->stat) {
if (stat & map->stat) {
unit = nouveau_subdev(subdev, map->unit);
if (unit && unit->intr)
unit->intr(unit);
- intr &= ~map->stat;
+ stat &= ~map->stat;
}
map++;
}
- if (intr) {
+ if (stat) {
nv_error(pmc, "unknown intr 0x%08x\n", stat);
}
}
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
index 8d759f830323..cedf33b02977 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
@@ -39,7 +39,6 @@ nv50_mc_intr[] = {
{ 0x00200000, NVDEV_SUBDEV_GPIO },
{ 0x04000000, NVDEV_ENGINE_DISP },
{ 0x80000000, NVDEV_ENGINE_SW },
- { 0x0000d101, NVDEV_SUBDEV_FB },
{},
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
index ceb5c83f9459..a001e4c4d38d 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
@@ -40,7 +40,6 @@ nv98_mc_intr[] = {
{ 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */
{ 0x04000000, NVDEV_ENGINE_DISP },
{ 0x80000000, NVDEV_ENGINE_SW },
- { 0x0040d101, NVDEV_SUBDEV_FB },
{},
};
diff --git a/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
index 92796682722d..c2b81e30a17d 100644
--- a/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
+++ b/trunk/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
@@ -36,7 +36,6 @@ nvc0_mc_intr[] = {
{ 0x00000100, NVDEV_ENGINE_FIFO },
{ 0x00001000, NVDEV_ENGINE_GR },
{ 0x00008000, NVDEV_ENGINE_BSP },
- { 0x00020000, NVDEV_ENGINE_VP },
{ 0x00100000, NVDEV_SUBDEV_TIMER },
{ 0x00200000, NVDEV_SUBDEV_GPIO },
{ 0x02000000, NVDEV_SUBDEV_LTCG },
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_abi16.c b/trunk/drivers/gpu/drm/nouveau/nouveau_abi16.c
index d48c02a36527..cc79c796afee 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -242,26 +242,14 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
if (unlikely(!abi16))
return -ENOMEM;
client = nv_client(abi16->client);
- device = nv_device(abi16->device);
- imem = nouveau_instmem(device);
- pfb = nouveau_fb(device);
-
- /* hack to allow channel engine type specification on kepler */
- if (device->card_type >= NV_E0) {
- if (init->fb_ctxdma_handle != ~0)
- init->fb_ctxdma_handle = NVE0_CHANNEL_IND_ENGINE_GR;
- else
- init->fb_ctxdma_handle = init->tt_ctxdma_handle;
-
- /* allow flips to be executed if this is a graphics channel */
- init->tt_ctxdma_handle = 0;
- if (init->fb_ctxdma_handle == NVE0_CHANNEL_IND_ENGINE_GR)
- init->tt_ctxdma_handle = 1;
- }
if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
return nouveau_abi16_put(abi16, -EINVAL);
+ device = nv_device(abi16->device);
+ imem = nouveau_instmem(device);
+ pfb = nouveau_fb(device);
+
/* allocate "abi16 channel" data and make up a handle for it */
init->channel = ffsll(~abi16->handles);
if (!init->channel--)
@@ -276,6 +264,11 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
abi16->handles |= (1 << init->channel);
/* create channel object and initialise dma and fence management */
+ if (device->card_type >= NV_E0) {
+ init->fb_ctxdma_handle = NVE0_CHANNEL_IND_ENGINE_GR;
+ init->tt_ctxdma_handle = 0;
+ }
+
ret = nouveau_channel_new(drm, cli, NVDRM_DEVICE, NVDRM_CHAN |
init->channel, init->fb_ctxdma_handle,
init->tt_ctxdma_handle, &chan->chan);
@@ -385,7 +378,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
struct nouveau_abi16_chan *chan, *temp;
struct nouveau_abi16_ntfy *ntfy;
struct nouveau_object *object;
- struct nv_dma_class args = {};
+ struct nv_dma_class args;
int ret;
if (unlikely(!abi16))
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_acpi.c b/trunk/drivers/gpu/drm/nouveau/nouveau_acpi.c
index d97f20069d3e..48783e14114c 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -35,14 +35,6 @@ static struct nouveau_dsm_priv {
acpi_handle rom_handle;
} nouveau_dsm_priv;
-bool nouveau_is_optimus(void) {
- return nouveau_dsm_priv.optimus_detected;
-}
-
-bool nouveau_is_v1_dsm(void) {
- return nouveau_dsm_priv.dsm_detected;
-}
-
#define NOUVEAU_DSM_HAS_MUX 0x1
#define NOUVEAU_DSM_HAS_OPT 0x2
@@ -191,7 +183,9 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero
static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
{
- if (!nouveau_dsm_priv.dsm_detected)
+ /* perhaps the _DSM functions are mutually exclusive, but prepare for
+ * the future */
+ if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected)
return 0;
if (id == VGA_SWITCHEROO_IGD)
return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA);
@@ -207,7 +201,7 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
/* Optimus laptops have the card already disabled in
* nouveau_switcheroo_set_state */
- if (!nouveau_dsm_priv.dsm_detected)
+ if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected)
return 0;
return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
@@ -289,24 +283,24 @@ static bool nouveau_dsm_detect(void)
has_optimus = 1;
}
- /* find the optimus DSM or the old v1 DSM */
- if (has_optimus == 1) {
+ if (vga_count == 2 && has_dsm && guid_valid) {
acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
&buffer);
- printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n",
+ printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
acpi_method_name);
- nouveau_dsm_priv.optimus_detected = true;
+ nouveau_dsm_priv.dsm_detected = true;
ret = true;
- } else if (vga_count == 2 && has_dsm && guid_valid) {
+ }
+
+ if (has_optimus == 1) {
acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
&buffer);
- printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
+ printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n",
acpi_method_name);
- nouveau_dsm_priv.dsm_detected = true;
+ nouveau_dsm_priv.optimus_detected = true;
ret = true;
}
-
return ret;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_acpi.h b/trunk/drivers/gpu/drm/nouveau/nouveau_acpi.h
index d0da230d7706..08af67722b57 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_acpi.h
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_acpi.h
@@ -4,8 +4,6 @@
#define ROM_BIOS_PAGE 4096
#if defined(CONFIG_ACPI)
-bool nouveau_is_optimus(void);
-bool nouveau_is_v1_dsm(void);
void nouveau_register_dsm_handler(void);
void nouveau_unregister_dsm_handler(void);
void nouveau_switcheroo_optimus_dsm(void);
@@ -13,8 +11,6 @@ int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
#else
-static inline bool nouveau_is_optimus(void) { return false; };
-static inline bool nouveau_is_v1_dsm(void) { return false; };
static inline void nouveau_register_dsm_handler(void) {}
static inline void nouveau_unregister_dsm_handler(void) {}
static inline void nouveau_switcheroo_optimus_dsm(void) {}
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_bios.c b/trunk/drivers/gpu/drm/nouveau/nouveau_bios.c
index 865eddfa30a7..09fdef235882 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -624,6 +624,206 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
return 0;
}
+/* BIT 'U'/'d' table encoder subtables have hashes matching them to
+ * a particular set of encoders.
+ *
+ * This function returns true if a particular DCB entry matches.
+ */
+bool
+bios_encoder_match(struct dcb_output *dcb, u32 hash)
+{
+ if ((hash & 0x000000f0) != (dcb->location << 4))
+ return false;
+ if ((hash & 0x0000000f) != dcb->type)
+ return false;
+ if (!(hash & (dcb->or << 16)))
+ return false;
+
+ switch (dcb->type) {
+ case DCB_OUTPUT_TMDS:
+ case DCB_OUTPUT_LVDS:
+ case DCB_OUTPUT_DP:
+ if (hash & 0x00c00000) {
+ if (!(hash & (dcb->sorconf.link << 22)))
+ return false;
+ }
+ default:
+ return true;
+ }
+}
+
+int
+nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk,
+ struct dcb_output *dcbent, int crtc)
+{
+ /*
+ * The display script table is located by the BIT 'U' table.
+ *
+ * It contains an array of pointers to various tables describing
+ * a particular output type. The first 32-bits of the output
+ * tables contains similar information to a DCB entry, and is
+ * used to decide whether that particular table is suitable for
+ * the output you want to access.
+ *
+ * The "record header length" field here seems to indicate the
+ * offset of the first configuration entry in the output tables.
+ * This is 10 on most cards I've seen, but 12 has been witnessed
+ * on DP cards, and there's another script pointer within the
+ * header.
+ *
+ * offset + 0 ( 8 bits): version
+ * offset + 1 ( 8 bits): header length
+ * offset + 2 ( 8 bits): record length
+ * offset + 3 ( 8 bits): number of records
+ * offset + 4 ( 8 bits): record header length
+ * offset + 5 (16 bits): pointer to first output script table
+ */
+
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nvbios *bios = &drm->vbios;
+ uint8_t *table = &bios->data[bios->display.script_table_ptr];
+ uint8_t *otable = NULL;
+ uint16_t script;
+ int i;
+
+ if (!bios->display.script_table_ptr) {
+ NV_ERROR(drm, "No pointer to output script table\n");
+ return 1;
+ }
+
+ /*
+ * Nothing useful has been in any of the pre-2.0 tables I've seen,
+ * so until they are, we really don't need to care.
+ */
+ if (table[0] < 0x20)
+ return 1;
+
+ if (table[0] != 0x20 && table[0] != 0x21) {
+ NV_ERROR(drm, "Output script table version 0x%02x unknown\n",
+ table[0]);
+ return 1;
+ }
+
+ /*
+ * The output script tables describing a particular output type
+ * look as follows:
+ *
+ * offset + 0 (32 bits): output this table matches (hash of DCB)
+ * offset + 4 ( 8 bits): unknown
+ * offset + 5 ( 8 bits): number of configurations
+ * offset + 6 (16 bits): pointer to some script
+ * offset + 8 (16 bits): pointer to some script
+ *
+ * headerlen == 10
+ * offset + 10 : configuration 0
+ *
+ * headerlen == 12
+ * offset + 10 : pointer to some script
+ * offset + 12 : configuration 0
+ *
+ * Each config entry is as follows:
+ *
+ * offset + 0 (16 bits): unknown, assumed to be a match value
+ * offset + 2 (16 bits): pointer to script table (clock set?)
+ * offset + 4 (16 bits): pointer to script table (reset?)
+ *
+ * There doesn't appear to be a count value to say how many
+ * entries exist in each script table, instead, a 0 value in
+ * the first 16-bit word seems to indicate both the end of the
+ * list and the default entry. The second 16-bit word in the
+ * script tables is a pointer to the script to execute.
+ */
+
+ NV_DEBUG(drm, "Searching for output entry for %d %d %d\n",
+ dcbent->type, dcbent->location, dcbent->or);
+ for (i = 0; i < table[3]; i++) {
+ otable = ROMPTR(dev, table[table[1] + (i * table[2])]);
+ if (otable && bios_encoder_match(dcbent, ROM32(otable[0])))
+ break;
+ }
+
+ if (!otable) {
+ NV_DEBUG(drm, "failed to match any output table\n");
+ return 1;
+ }
+
+ 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]) == type)
+ break;
+ }
+
+ if (i == otable[5]) {
+ NV_ERROR(drm, "Table 0x%04x not found for %d/%d, "
+ "using first\n",
+ type, dcbent->type, dcbent->or);
+ i = 0;
+ }
+ }
+
+ if (pclk == 0) {
+ script = ROM16(otable[6]);
+ if (!script) {
+ NV_DEBUG(drm, "output script 0 not found\n");
+ return 1;
+ }
+
+ NV_DEBUG(drm, "0x%04X: parsing output script 0\n", script);
+ nouveau_bios_run_init_table(dev, script, dcbent, crtc);
+ } else
+ if (pclk == -1) {
+ script = ROM16(otable[8]);
+ if (!script) {
+ NV_DEBUG(drm, "output script 1 not found\n");
+ return 1;
+ }
+
+ NV_DEBUG(drm, "0x%04X: parsing output script 1\n", script);
+ nouveau_bios_run_init_table(dev, script, dcbent, crtc);
+ } else
+ if (pclk == -2) {
+ if (table[4] >= 12)
+ script = ROM16(otable[10]);
+ else
+ script = 0;
+ if (!script) {
+ NV_DEBUG(drm, "output script 2 not found\n");
+ return 1;
+ }
+
+ NV_DEBUG(drm, "0x%04X: parsing output script 2\n", script);
+ nouveau_bios_run_init_table(dev, script, dcbent, crtc);
+ } else
+ if (pclk > 0) {
+ script = ROM16(otable[table[4] + i*6 + 2]);
+ if (script)
+ script = clkcmptable(bios, script, pclk);
+ if (!script) {
+ NV_DEBUG(drm, "clock script 0 not found\n");
+ return 1;
+ }
+
+ NV_DEBUG(drm, "0x%04X: parsing clock script 0\n", script);
+ nouveau_bios_run_init_table(dev, script, dcbent, crtc);
+ } else
+ if (pclk < 0) {
+ script = ROM16(otable[table[4] + i*6 + 4]);
+ if (script)
+ script = clkcmptable(bios, script, -pclk);
+ if (!script) {
+ NV_DEBUG(drm, "clock script 1 not found\n");
+ return 1;
+ }
+
+ NV_DEBUG(drm, "0x%04X: parsing clock script 1\n", script);
+ nouveau_bios_run_init_table(dev, script, dcbent, crtc);
+ }
+
+ return 0;
+}
+
+
int run_tmds_table(struct drm_device *dev, struct dcb_output *dcbent, int head, int pxclk)
{
/*
@@ -1012,6 +1212,31 @@ static int parse_bit_tmds_tbl_entry(struct drm_device *dev, struct nvbios *bios,
return 0;
}
+static int
+parse_bit_U_tbl_entry(struct drm_device *dev, struct nvbios *bios,
+ struct bit_entry *bitentry)
+{
+ /*
+ * Parses the pointer to the G80 output script tables
+ *
+ * Starting at bitentry->offset:
+ *
+ * offset + 0 (16 bits): output script table pointer
+ */
+
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ uint16_t outputscripttableptr;
+
+ if (bitentry->length != 3) {
+ NV_ERROR(drm, "Do not understand BIT U table\n");
+ return -EINVAL;
+ }
+
+ outputscripttableptr = ROM16(bios->data[bitentry->offset]);
+ bios->display.script_table_ptr = outputscripttableptr;
+ return 0;
+}
+
struct bit_table {
const char id;
int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *);
@@ -1088,6 +1313,7 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset)
parse_bit_table(bios, bitoffset, &BIT_TABLE('M', M)); /* memory? */
parse_bit_table(bios, bitoffset, &BIT_TABLE('L', lvds));
parse_bit_table(bios, bitoffset, &BIT_TABLE('T', tmds));
+ parse_bit_table(bios, bitoffset, &BIT_TABLE('U', U));
return 0;
}
@@ -2098,7 +2324,7 @@ nouveau_run_vbios_init(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvbios *bios = &drm->vbios;
- int ret = 0;
+ int i, ret = 0;
/* Reset the BIOS head to 0. */
bios->state.crtchead = 0;
@@ -2111,6 +2337,13 @@ nouveau_run_vbios_init(struct drm_device *dev)
bios->fp.lvds_init_run = false;
}
+ if (nv_device(drm->device)->card_type >= NV_50) {
+ for (i = 0; bios->execute && i < bios->dcb.entries; i++) {
+ nouveau_bios_run_display_table(dev, 0, 0,
+ &bios->dcb.entry[i], -1);
+ }
+ }
+
return ret;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_bios.h b/trunk/drivers/gpu/drm/nouveau/nouveau_bios.h
index f68c54ca422f..3befbb821a56 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -127,6 +127,12 @@ struct nvbios {
int crtchead;
} state;
+ struct {
+ struct dcb_output *output;
+ int crtc;
+ uint16_t script_table_ptr;
+ } display;
+
struct {
uint16_t fptablepointer; /* also used by tmds */
uint16_t fpxlatetableptr;
@@ -179,6 +185,8 @@ void nouveau_bios_takedown(struct drm_device *dev);
int nouveau_run_vbios_init(struct drm_device *);
struct dcb_connector_table_entry *
nouveau_bios_connector_entry(struct drm_device *, int index);
+int nouveau_bios_run_display_table(struct drm_device *, u16 id, int clk,
+ struct dcb_output *, int crtc);
bool nouveau_bios_fp_mode(struct drm_device *, struct drm_display_mode *);
uint8_t *nouveau_bios_embedded_edid(struct drm_device *);
int nouveau_bios_parse_lvds_table(struct drm_device *, int pxclk,
@@ -187,5 +195,6 @@ int run_tmds_table(struct drm_device *, struct dcb_output *,
int head, int pxclk);
int call_lvds_script(struct drm_device *, struct dcb_output *, int head,
enum LVDS_script, int pxclk);
+bool bios_encoder_match(struct dcb_output *, u32 hash);
#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_chan.c b/trunk/drivers/gpu/drm/nouveau/nouveau_chan.c
index 174300b6a02e..c1d7301c0e9c 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -76,8 +76,6 @@ nouveau_channel_del(struct nouveau_channel **pchan)
nouveau_object_del(client, NVDRM_DEVICE, chan->push.handle);
nouveau_bo_vma_del(chan->push.buffer, &chan->push.vma);
nouveau_bo_unmap(chan->push.buffer);
- if (chan->push.buffer && chan->push.buffer->pin_refcnt)
- nouveau_bo_unpin(chan->push.buffer);
nouveau_bo_ref(NULL, &chan->push.buffer);
kfree(chan);
}
@@ -269,7 +267,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
struct nouveau_fb *pfb = nouveau_fb(device);
struct nouveau_software_chan *swch;
struct nouveau_object *object;
- struct nv_dma_class args = {};
+ struct nv_dma_class args;
int ret, i;
/* allocate dma objects to cover all allowed vram, and gart */
@@ -348,7 +346,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
/* allocate software object class (used for fences on <= nv05, and
* to signal flip completion), bind it to a subchannel.
*/
- if ((device->card_type < NV_E0) || gart /* nve0: want_nvsw */) {
+ if (chan != chan->drm->cechan) {
ret = nouveau_object_new(nv_object(client), chan->handle,
NvSw, nouveau_abi16_swclass(chan->drm),
NULL, 0, &object);
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c b/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c
index 98d7e9238f6d..9a6e2cb282dc 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -110,6 +110,7 @@ nouveau_connector_destroy(struct drm_connector *connector)
dev = nv_connector->base.dev;
drm = nouveau_drm(dev);
gpio = nouveau_gpio(drm->device);
+ NV_DEBUG(drm, "\n");
if (gpio && nv_connector->hpd != DCB_GPIO_UNUSED) {
gpio->isr_del(gpio, 0, nv_connector->hpd, 0xff,
@@ -928,6 +929,8 @@ nouveau_connector_create(struct drm_device *dev, int index)
int type, ret = 0;
bool dummy;
+ NV_DEBUG(drm, "\n");
+
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
nv_connector = nouveau_connector(connector);
if (nv_connector->index == index)
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_connector.h b/trunk/drivers/gpu/drm/nouveau/nouveau_connector.h
index 20eb84cce9e6..ebdb87670a8f 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -28,7 +28,6 @@
#define __NOUVEAU_CONNECTOR_H__
#include
-#include "nouveau_crtc.h"
struct nouveau_i2c_port;
@@ -81,21 +80,6 @@ static inline struct nouveau_connector *nouveau_connector(
return container_of(con, struct nouveau_connector, base);
}
-static inline struct nouveau_connector *
-nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
-{
- struct drm_device *dev = nv_crtc->base.dev;
- struct drm_connector *connector;
- struct drm_crtc *crtc = to_drm_crtc(nv_crtc);
-
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (connector->encoder && connector->encoder->crtc == crtc)
- return nouveau_connector(connector);
- }
-
- return NULL;
-}
-
struct drm_connector *
nouveau_connector_create(struct drm_device *, int index);
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_crtc.h b/trunk/drivers/gpu/drm/nouveau/nouveau_crtc.h
index d1e5890784d7..e6d0d1eb0133 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_crtc.h
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_crtc.h
@@ -82,6 +82,16 @@ static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc)
return &crtc->base;
}
+int nv50_crtc_create(struct drm_device *dev, int index);
+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);
#endif /* __NOUVEAU_CRTC_H__ */
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_display.c b/trunk/drivers/gpu/drm/nouveau/nouveau_display.c
index e4188f24fc75..86124b131f4f 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -98,12 +98,12 @@ nouveau_framebuffer_init(struct drm_device *dev,
nv_fb->r_dma = NvEvoVRAM_LP;
switch (fb->depth) {
- case 8: nv_fb->r_format = 0x1e00; break;
- case 15: nv_fb->r_format = 0xe900; break;
- case 16: nv_fb->r_format = 0xe800; break;
+ case 8: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_8; break;
+ case 15: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_15; break;
+ case 16: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_16; break;
case 24:
- case 32: nv_fb->r_format = 0xcf00; break;
- case 30: nv_fb->r_format = 0xd100; break;
+ case 32: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_24; break;
+ case 30: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_30; break;
default:
NV_ERROR(drm, "unknown depth %d\n", fb->depth);
return -EINVAL;
@@ -324,7 +324,7 @@ nouveau_display_create(struct drm_device *dev)
disp->underscan_vborder_property =
drm_property_create_range(dev, 0, "underscan vborder", 0, 128);
- if (gen >= 1) {
+ if (gen == 1) {
disp->vibrant_hue_property =
drm_property_create(dev, DRM_MODE_PROP_RANGE,
"vibrant hue", 2);
@@ -366,7 +366,10 @@ nouveau_display_create(struct drm_device *dev)
if (nv_device(drm->device)->card_type < NV_50)
ret = nv04_display_create(dev);
else
+ if (nv_device(drm->device)->card_type < NV_D0)
ret = nv50_display_create(dev);
+ else
+ ret = nvd0_display_create(dev);
if (ret)
goto disp_create_err;
@@ -397,12 +400,11 @@ nouveau_display_destroy(struct drm_device *dev)
nouveau_backlight_exit(dev);
drm_vblank_cleanup(dev);
- drm_kms_helper_poll_fini(dev);
- drm_mode_config_cleanup(dev);
-
if (disp->dtor)
disp->dtor(dev);
+ drm_kms_helper_poll_fini(dev);
+ drm_mode_config_cleanup(dev);
nouveau_drm(dev)->display = NULL;
kfree(disp);
}
@@ -657,7 +659,10 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
/* Emit a page flip */
if (nv_device(drm->device)->card_type >= NV_50) {
- ret = nv50_display_flip_next(crtc, fb, chan, 0);
+ if (nv_device(drm->device)->card_type >= NV_D0)
+ ret = nvd0_display_flip_next(crtc, fb, chan, 0);
+ else
+ ret = nv50_display_flip_next(crtc, fb, chan);
if (ret) {
mutex_unlock(&chan->cli->mutex);
goto fail_unreserve;
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_dp.c b/trunk/drivers/gpu/drm/nouveau/nouveau_dp.c
index 59838651ee8f..978a108ba7a1 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -30,17 +30,60 @@
#include "nouveau_encoder.h"
#include "nouveau_crtc.h"
-#include
-
#include
#include
+u8 *
+nouveau_dp_bios_data(struct drm_device *dev, struct dcb_output *dcb, u8 **entry)
+{
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct bit_entry d;
+ u8 *table;
+ int i;
+
+ if (bit_table(dev, 'd', &d)) {
+ NV_ERROR(drm, "BIT 'd' table not found\n");
+ return NULL;
+ }
+
+ if (d.version != 1) {
+ NV_ERROR(drm, "BIT 'd' table version %d unknown\n", d.version);
+ return NULL;
+ }
+
+ table = ROMPTR(dev, d.data[0]);
+ if (!table) {
+ NV_ERROR(drm, "displayport table pointer invalid\n");
+ return NULL;
+ }
+
+ switch (table[0]) {
+ case 0x20:
+ case 0x21:
+ case 0x30:
+ case 0x40:
+ break;
+ default:
+ NV_ERROR(drm, "displayport table 0x%02x unknown\n", table[0]);
+ return NULL;
+ }
+
+ for (i = 0; i < table[3]; i++) {
+ *entry = ROMPTR(dev, table[table[1] + (i * table[2])]);
+ if (*entry && bios_encoder_match(dcb, ROM32((*entry)[0])))
+ return table;
+ }
+
+ NV_ERROR(drm, "displayport encoder table not found\n");
+ return NULL;
+}
+
/******************************************************************************
* link training
*****************************************************************************/
struct dp_state {
struct nouveau_i2c_port *auxch;
- struct nouveau_object *core;
+ struct dp_train_func *func;
struct dcb_output *dcb;
int crtc;
u8 *dpcd;
@@ -54,20 +97,13 @@ static void
dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct dcb_output *dcb = dp->dcb;
- const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
- const u32 moff = (dp->crtc << 3) | (link << 2) | or;
u8 sink[2];
- u32 data;
NV_DEBUG(drm, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
/* set desired link configuration on the source */
- data = ((dp->link_bw / 27000) << 8) | dp->link_nr;
- if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)
- data |= NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH;
-
- nv_call(dp->core, NV94_DISP_SOR_DP_LNKCTL + moff, data);
+ dp->func->link_set(dev, dp->dcb, dp->crtc, dp->link_nr, dp->link_bw,
+ dp->dpcd[2] & DP_ENHANCED_FRAME_CAP);
/* inform the sink of the new configuration */
sink[0] = dp->link_bw / 27000;
@@ -82,14 +118,11 @@ static void
dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 pattern)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct dcb_output *dcb = dp->dcb;
- const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
- const u32 moff = (dp->crtc << 3) | (link << 2) | or;
u8 sink_tp;
NV_DEBUG(drm, "training pattern %d\n", pattern);
- nv_call(dp->core, NV94_DISP_SOR_DP_TRAIN + moff, pattern);
+ dp->func->train_set(dev, dp->dcb, pattern);
nv_rdaux(dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
sink_tp &= ~DP_TRAINING_PATTERN_MASK;
@@ -101,9 +134,6 @@ static int
dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct dcb_output *dcb = dp->dcb;
- const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
- const u32 moff = (dp->crtc << 3) | (link << 2) | or;
int i;
for (i = 0; i < dp->link_nr; i++) {
@@ -118,8 +148,7 @@ dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
NV_DEBUG(drm, "config lane %d %02x\n", i, dp->conf[i]);
-
- nv_call(dp->core, NV94_DISP_SOR_DP_DRVCTL(i) + moff, (lvsw << 8) | lpre);
+ dp->func->train_adj(dev, dp->dcb, i, lvsw, lpre);
}
return nv_wraux(dp->auxch, DP_TRAINING_LANE0_SET, dp->conf, 4);
@@ -205,32 +234,59 @@ dp_link_train_eq(struct drm_device *dev, struct dp_state *dp)
}
static void
-dp_link_train_init(struct drm_device *dev, struct dp_state *dp, bool spread)
+dp_set_downspread(struct drm_device *dev, struct dp_state *dp, bool enable)
{
- struct dcb_output *dcb = dp->dcb;
- const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
- const u32 moff = (dp->crtc << 3) | (link << 2) | or;
-
- nv_call(dp->core, NV94_DISP_SOR_DP_TRAIN + moff, (spread ?
- NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_ON :
- NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_OFF) |
- NV94_DISP_SOR_DP_TRAIN_OP_INIT);
+ u16 script = 0x0000;
+ u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry);
+ if (table) {
+ if (table[0] >= 0x20 && table[0] <= 0x30) {
+ if (enable) script = ROM16(entry[12]);
+ else script = ROM16(entry[14]);
+ } else
+ if (table[0] == 0x40) {
+ if (enable) script = ROM16(entry[11]);
+ else script = ROM16(entry[13]);
+ }
+ }
+
+ nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
+}
+
+static void
+dp_link_train_init(struct drm_device *dev, struct dp_state *dp)
+{
+ u16 script = 0x0000;
+ u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry);
+ if (table) {
+ if (table[0] >= 0x20 && table[0] <= 0x30)
+ script = ROM16(entry[6]);
+ else
+ if (table[0] == 0x40)
+ script = ROM16(entry[5]);
+ }
+
+ nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
}
static void
dp_link_train_fini(struct drm_device *dev, struct dp_state *dp)
{
- struct dcb_output *dcb = dp->dcb;
- const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
- const u32 moff = (dp->crtc << 3) | (link << 2) | or;
+ u16 script = 0x0000;
+ u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry);
+ if (table) {
+ if (table[0] >= 0x20 && table[0] <= 0x30)
+ script = ROM16(entry[8]);
+ else
+ if (table[0] == 0x40)
+ script = ROM16(entry[7]);
+ }
- nv_call(dp->core, NV94_DISP_SOR_DP_TRAIN + moff,
- NV94_DISP_SOR_DP_TRAIN_OP_FINI);
+ nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
}
static bool
nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
- struct nouveau_object *core)
+ struct dp_train_func *func)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
@@ -248,7 +304,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
if (!dp.auxch)
return false;
- dp.core = core;
+ dp.func = func;
dp.dcb = nv_encoder->dcb;
dp.crtc = nv_crtc->index;
dp.dpcd = nv_encoder->dp.dpcd;
@@ -262,8 +318,11 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
*/
gpio->irq(gpio, 0, nv_connector->hpd, 0xff, false);
- /* enable down-spreading and execute pre-train script from vbios */
- dp_link_train_init(dev, &dp, nv_encoder->dp.dpcd[3] & 1);
+ /* enable down-spreading, if possible */
+ dp_set_downspread(dev, &dp, nv_encoder->dp.dpcd[3] & 1);
+
+ /* execute pre-train script from vbios */
+ dp_link_train_init(dev, &dp);
/* start off at highest link rate supported by encoder and display */
while (*link_bw > nv_encoder->dp.link_bw)
@@ -306,7 +365,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
void
nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
- struct nouveau_object *core)
+ struct dp_train_func *func)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
@@ -326,7 +385,7 @@ nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
nv_wraux(auxch, DP_SET_POWER, &status, 1);
if (mode == DRM_MODE_DPMS_ON)
- nouveau_dp_link_train(encoder, datarate, core);
+ nouveau_dp_link_train(encoder, datarate, func);
}
static void
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_drm.c b/trunk/drivers/gpu/drm/nouveau/nouveau_drm.c
index a7529b372381..8244863cc049 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -49,6 +49,8 @@
#include "nouveau_fbcon.h"
#include "nouveau_fence.h"
+#include "nouveau_ttm.h"
+
MODULE_PARM_DESC(config, "option string to pass to driver core");
static char *nouveau_config;
module_param_named(config, nouveau_config, charp, 0400);
@@ -146,7 +148,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
arg0 = NVE0_CHANNEL_IND_ENGINE_GR;
- arg1 = 1;
+ arg1 = 0;
} else {
arg0 = NvDmaFB;
arg1 = NvDmaTT;
@@ -393,12 +395,17 @@ nouveau_drm_remove(struct pci_dev *pdev)
}
int
-nouveau_do_suspend(struct drm_device *dev)
+nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state)
{
+ struct drm_device *dev = pci_get_drvdata(pdev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_cli *cli;
int ret;
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF ||
+ pm_state.event == PM_EVENT_PRETHAW)
+ return 0;
+
if (dev->mode_config.num_crtc) {
NV_INFO(drm, "suspending fbcon...\n");
nouveau_fbcon_set_suspend(dev, 1);
@@ -429,6 +436,13 @@ nouveau_do_suspend(struct drm_device *dev)
goto fail_client;
nouveau_agp_fini(drm);
+
+ pci_save_state(pdev);
+ if (pm_state.event == PM_EVENT_SUSPEND) {
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ }
+
return 0;
fail_client:
@@ -443,33 +457,24 @@ nouveau_do_suspend(struct drm_device *dev)
return ret;
}
-int nouveau_pmops_suspend(struct device *dev)
+int
+nouveau_drm_resume(struct pci_dev *pdev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_cli *cli;
int ret;
- if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
- ret = nouveau_do_suspend(drm_dev);
+ NV_INFO(drm, "re-enabling device...\n");
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ ret = pci_enable_device(pdev);
if (ret)
return ret;
-
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
-
- return 0;
-}
-
-int
-nouveau_do_resume(struct drm_device *dev)
-{
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_cli *cli;
-
- NV_INFO(drm, "re-enabling device...\n");
+ pci_set_master(pdev);
nouveau_agp_reset(drm);
@@ -495,42 +500,6 @@ nouveau_do_resume(struct drm_device *dev)
return 0;
}
-int nouveau_pmops_resume(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
- int ret;
-
- if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
- return 0;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- ret = pci_enable_device(pdev);
- if (ret)
- return ret;
- pci_set_master(pdev);
-
- return nouveau_do_resume(drm_dev);
-}
-
-static int nouveau_pmops_freeze(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
-
- return nouveau_do_suspend(drm_dev);
-}
-
-static int nouveau_pmops_thaw(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
-
- return nouveau_do_resume(drm_dev);
-}
-
-
static int
nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
{
@@ -683,22 +652,14 @@ nouveau_drm_pci_table[] = {
{}
};
-static const struct dev_pm_ops nouveau_pm_ops = {
- .suspend = nouveau_pmops_suspend,
- .resume = nouveau_pmops_resume,
- .freeze = nouveau_pmops_freeze,
- .thaw = nouveau_pmops_thaw,
- .poweroff = nouveau_pmops_freeze,
- .restore = nouveau_pmops_resume,
-};
-
static struct pci_driver
nouveau_drm_pci_driver = {
.name = "nouveau",
.id_table = nouveau_drm_pci_table,
.probe = nouveau_drm_probe,
.remove = nouveau_drm_remove,
- .driver.pm = &nouveau_pm_ops,
+ .suspend = nouveau_drm_suspend,
+ .resume = nouveau_drm_resume,
};
static int __init
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_drm.h b/trunk/drivers/gpu/drm/nouveau/nouveau_drm.h
index aa89eb938b47..a10169927086 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -129,8 +129,8 @@ nouveau_dev(struct drm_device *dev)
return nv_device(nouveau_drm(dev)->device);
}
-int nouveau_pmops_suspend(struct device *);
-int nouveau_pmops_resume(struct device *);
+int nouveau_drm_suspend(struct pci_dev *, pm_message_t);
+int nouveau_drm_resume(struct pci_dev *);
#define NV_FATAL(cli, fmt, args...) nv_fatal((cli), fmt, ##args)
#define NV_ERROR(cli, fmt, args...) nv_error((cli), fmt, ##args)
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_encoder.h b/trunk/drivers/gpu/drm/nouveau/nouveau_encoder.h
index d0d95bd511ab..6a17bf2ba9a4 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -93,9 +93,14 @@ get_slave_funcs(struct drm_encoder *enc)
/* nouveau_dp.c */
bool nouveau_dp_detect(struct drm_encoder *);
void nouveau_dp_dpms(struct drm_encoder *, int mode, u32 datarate,
- struct nouveau_object *);
+ struct dp_train_func *);
+u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_output *, u8 **);
struct nouveau_connector *
nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
+int nv50_sor_create(struct drm_connector *, struct dcb_output *);
+void nv50_sor_dp_calc_tu(struct drm_device *, int, int, u32, u32);
+int nv50_dac_create(struct drm_connector *, struct dcb_output *);
+
#endif /* __NOUVEAU_ENCODER_H__ */
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_hdmi.c b/trunk/drivers/gpu/drm/nouveau/nouveau_hdmi.c
new file mode 100644
index 000000000000..2c672cebc889
--- /dev/null
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_hdmi.c
@@ -0,0 +1,261 @@
+/*
+ * 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 "nouveau_drm.h"
+#include "nouveau_connector.h"
+#include "nouveau_encoder.h"
+#include "nouveau_crtc.h"
+
+static bool
+hdmi_sor(struct drm_encoder *encoder)
+{
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ if (nv_device(drm->device)->chipset < 0xa3 ||
+ nv_device(drm->device)->chipset == 0xaa ||
+ nv_device(drm->device)->chipset == 0xac)
+ return false;
+ return true;
+}
+
+static inline u32
+hdmi_base(struct drm_encoder *encoder)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
+ if (!hdmi_sor(encoder))
+ return 0x616500 + (nv_crtc->index * 0x800);
+ return 0x61c500 + (nv_encoder->or * 0x800);
+}
+
+static void
+hdmi_wr32(struct drm_encoder *encoder, u32 reg, u32 val)
+{
+ struct nouveau_device *device = nouveau_dev(encoder->dev);
+ nv_wr32(device, hdmi_base(encoder) + reg, val);
+}
+
+static u32
+hdmi_rd32(struct drm_encoder *encoder, u32 reg)
+{
+ struct nouveau_device *device = nouveau_dev(encoder->dev);
+ return nv_rd32(device, hdmi_base(encoder) + reg);
+}
+
+static u32
+hdmi_mask(struct drm_encoder *encoder, u32 reg, u32 mask, u32 val)
+{
+ u32 tmp = hdmi_rd32(encoder, reg);
+ hdmi_wr32(encoder, reg, (tmp & ~mask) | val);
+ return tmp;
+}
+
+static void
+nouveau_audio_disconnect(struct drm_encoder *encoder)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_device *device = nouveau_dev(encoder->dev);
+ u32 or = nv_encoder->or * 0x800;
+
+ if (hdmi_sor(encoder))
+ nv_mask(device, 0x61c448 + or, 0x00000003, 0x00000000);
+}
+
+static void
+nouveau_audio_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_device *device = nouveau_dev(encoder->dev);
+ struct nouveau_connector *nv_connector;
+ u32 or = nv_encoder->or * 0x800;
+ int i;
+
+ nv_connector = nouveau_encoder_connector_get(nv_encoder);
+ if (!drm_detect_monitor_audio(nv_connector->edid)) {
+ nouveau_audio_disconnect(encoder);
+ return;
+ }
+
+ if (hdmi_sor(encoder)) {
+ nv_mask(device, 0x61c448 + or, 0x00000001, 0x00000001);
+
+ drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
+ if (nv_connector->base.eld[0]) {
+ u8 *eld = nv_connector->base.eld;
+ for (i = 0; i < eld[2] * 4; i++)
+ nv_wr32(device, 0x61c440 + or, (i << 8) | eld[i]);
+ for (i = eld[2] * 4; i < 0x60; i++)
+ nv_wr32(device, 0x61c440 + or, (i << 8) | 0x00);
+ nv_mask(device, 0x61c448 + or, 0x00000002, 0x00000002);
+ }
+ }
+}
+
+static void
+nouveau_hdmi_infoframe(struct drm_encoder *encoder, u32 ctrl, u8 *frame)
+{
+ /* calculate checksum for the infoframe */
+ u8 sum = 0, i;
+ for (i = 0; i < frame[2]; i++)
+ sum += frame[i];
+ frame[3] = 256 - sum;
+
+ /* disable infoframe, and write header */
+ hdmi_mask(encoder, ctrl + 0x00, 0x00000001, 0x00000000);
+ hdmi_wr32(encoder, ctrl + 0x08, *(u32 *)frame & 0xffffff);
+
+ /* register scans tell me the audio infoframe has only one set of
+ * subpack regs, according to tegra (gee nvidia, it'd be nice if we
+ * could get those docs too!), the hdmi block pads out the rest of
+ * the packet on its own.
+ */
+ if (ctrl == 0x020)
+ frame[2] = 6;
+
+ /* write out checksum and data, weird weird 7 byte register pairs */
+ for (i = 0; i < frame[2] + 1; i += 7) {
+ u32 rsubpack = ctrl + 0x0c + ((i / 7) * 8);
+ u32 *subpack = (u32 *)&frame[3 + i];
+ hdmi_wr32(encoder, rsubpack + 0, subpack[0]);
+ hdmi_wr32(encoder, rsubpack + 4, subpack[1] & 0xffffff);
+ }
+
+ /* enable the infoframe */
+ hdmi_mask(encoder, ctrl, 0x00000001, 0x00000001);
+}
+
+static void
+nouveau_hdmi_video_infoframe(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ const u8 Y = 0, A = 0, B = 0, S = 0, C = 0, M = 0, R = 0;
+ const u8 ITC = 0, EC = 0, Q = 0, SC = 0, VIC = 0, PR = 0;
+ const u8 bar_top = 0, bar_bottom = 0, bar_left = 0, bar_right = 0;
+ u8 frame[20];
+
+ frame[0x00] = 0x82; /* AVI infoframe */
+ frame[0x01] = 0x02; /* version */
+ frame[0x02] = 0x0d; /* length */
+ frame[0x03] = 0x00;
+ frame[0x04] = (Y << 5) | (A << 4) | (B << 2) | S;
+ frame[0x05] = (C << 6) | (M << 4) | R;
+ frame[0x06] = (ITC << 7) | (EC << 4) | (Q << 2) | SC;
+ frame[0x07] = VIC;
+ frame[0x08] = PR;
+ frame[0x09] = bar_top & 0xff;
+ frame[0x0a] = bar_top >> 8;
+ frame[0x0b] = bar_bottom & 0xff;
+ frame[0x0c] = bar_bottom >> 8;
+ frame[0x0d] = bar_left & 0xff;
+ frame[0x0e] = bar_left >> 8;
+ frame[0x0f] = bar_right & 0xff;
+ frame[0x10] = bar_right >> 8;
+ frame[0x11] = 0x00;
+ frame[0x12] = 0x00;
+ frame[0x13] = 0x00;
+
+ nouveau_hdmi_infoframe(encoder, 0x020, frame);
+}
+
+static void
+nouveau_hdmi_audio_infoframe(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ const u8 CT = 0x00, CC = 0x01, ceaSS = 0x00, SF = 0x00, FMT = 0x00;
+ const u8 CA = 0x00, DM_INH = 0, LSV = 0x00;
+ u8 frame[12];
+
+ frame[0x00] = 0x84; /* Audio infoframe */
+ frame[0x01] = 0x01; /* version */
+ frame[0x02] = 0x0a; /* length */
+ frame[0x03] = 0x00;
+ frame[0x04] = (CT << 4) | CC;
+ frame[0x05] = (SF << 2) | ceaSS;
+ frame[0x06] = FMT;
+ frame[0x07] = CA;
+ frame[0x08] = (DM_INH << 7) | (LSV << 3);
+ frame[0x09] = 0x00;
+ frame[0x0a] = 0x00;
+ frame[0x0b] = 0x00;
+
+ nouveau_hdmi_infoframe(encoder, 0x000, frame);
+}
+
+static void
+nouveau_hdmi_disconnect(struct drm_encoder *encoder)
+{
+ nouveau_audio_disconnect(encoder);
+
+ /* disable audio and avi infoframes */
+ hdmi_mask(encoder, 0x000, 0x00000001, 0x00000000);
+ hdmi_mask(encoder, 0x020, 0x00000001, 0x00000000);
+
+ /* disable hdmi */
+ hdmi_mask(encoder, 0x0a4, 0x40000000, 0x00000000);
+}
+
+void
+nouveau_hdmi_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct nouveau_device *device = nouveau_dev(encoder->dev);
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_connector *nv_connector;
+ u32 max_ac_packet, rekey;
+
+ nv_connector = nouveau_encoder_connector_get(nv_encoder);
+ if (!mode || !nv_connector || !nv_connector->edid ||
+ !drm_detect_hdmi_monitor(nv_connector->edid)) {
+ nouveau_hdmi_disconnect(encoder);
+ return;
+ }
+
+ nouveau_hdmi_video_infoframe(encoder, mode);
+ nouveau_hdmi_audio_infoframe(encoder, mode);
+
+ hdmi_mask(encoder, 0x0d0, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
+ hdmi_mask(encoder, 0x068, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
+ hdmi_mask(encoder, 0x078, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
+
+ nv_mask(device, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
+ nv_mask(device, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
+ nv_mask(device, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
+
+ /* value matches nvidia binary driver, and tegra constant */
+ rekey = 56;
+
+ max_ac_packet = mode->htotal - mode->hdisplay;
+ max_ac_packet -= rekey;
+ max_ac_packet -= 18; /* constant from tegra */
+ max_ac_packet /= 32;
+
+ /* enable hdmi */
+ hdmi_mask(encoder, 0x0a4, 0x5f1f003f, 0x40000000 | /* enable */
+ 0x1f000000 | /* unknown */
+ max_ac_packet << 16 |
+ rekey);
+
+ nouveau_audio_mode_set(encoder, mode);
+}
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_irq.c b/trunk/drivers/gpu/drm/nouveau/nouveau_irq.c
index 1303680affd3..1d8cb506a28a 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -60,6 +60,18 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
return IRQ_NONE;
nv_subdev(pmc)->intr(nv_subdev(pmc));
+
+ if (dev->mode_config.num_crtc) {
+ if (device->card_type >= NV_D0) {
+ if (nv_rd32(device, 0x000100) & 0x04000000)
+ nvd0_display_intr(dev);
+ } else
+ if (device->card_type >= NV_50) {
+ if (nv_rd32(device, 0x000100) & 0x04000000)
+ nv50_display_intr(dev);
+ }
+ }
+
return IRQ_HANDLED;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_prime.c b/trunk/drivers/gpu/drm/nouveau/nouveau_prime.c
index 3543fec2355e..366462cf8a2c 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_prime.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_prime.c
@@ -155,6 +155,10 @@ nouveau_prime_new(struct drm_device *dev,
return ret;
nvbo = *pnvbo;
+ /* we restrict allowed domains on nv50+ to only the types
+ * that were requested at creation time. not possibly on
+ * earlier chips without busting the ABI.
+ */
nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_GART;
nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size);
if (!nvbo->gem) {
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_vga.c b/trunk/drivers/gpu/drm/nouveau/nouveau_vga.c
index 25d3495725eb..6f0ac64873df 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -31,11 +31,12 @@ nouveau_switcheroo_set_state(struct pci_dev *pdev,
enum vga_switcheroo_state state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
+ pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
- nouveau_pmops_resume(&pdev->dev);
+ nouveau_drm_resume(pdev);
drm_kms_helper_poll_enable(dev);
dev->switch_power_state = DRM_SWITCH_POWER_ON;
} else {
@@ -43,7 +44,7 @@ nouveau_switcheroo_set_state(struct pci_dev *pdev,
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
drm_kms_helper_poll_disable(dev);
nouveau_switcheroo_optimus_dsm();
- nouveau_pmops_suspend(&pdev->dev);
+ nouveau_drm_suspend(pdev, pmm);
dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
}
diff --git a/trunk/drivers/gpu/drm/nouveau/nv04_crtc.c b/trunk/drivers/gpu/drm/nouveau/nv04_crtc.c
index 6578cd28c556..82a0d9c6cda3 100644
--- a/trunk/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/trunk/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -730,7 +730,6 @@ static void nv_crtc_destroy(struct drm_crtc *crtc)
drm_crtc_cleanup(crtc);
nouveau_bo_unmap(nv_crtc->cursor.nvbo);
- nouveau_bo_unpin(nv_crtc->cursor.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
kfree(nv_crtc);
}
@@ -1057,11 +1056,8 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
0, 0x0000, NULL, &nv_crtc->cursor.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
- if (!ret) {
+ if (!ret)
ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
- if (ret)
- nouveau_bo_unpin(nv_crtc->cursor.nvbo);
- }
if (ret)
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
}
diff --git a/trunk/drivers/gpu/drm/nouveau/nv04_display.c b/trunk/drivers/gpu/drm/nouveau/nv04_display.c
index 2cd6fb8c548e..846050f04c23 100644
--- a/trunk/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/trunk/drivers/gpu/drm/nouveau/nv04_display.c
@@ -60,6 +60,8 @@ nv04_display_create(struct drm_device *dev)
struct nv04_display *disp;
int i, ret;
+ NV_DEBUG(drm, "\n");
+
disp = kzalloc(sizeof(*disp), GFP_KERNEL);
if (!disp)
return -ENOMEM;
@@ -130,10 +132,13 @@ nv04_display_create(struct drm_device *dev)
void
nv04_display_destroy(struct drm_device *dev)
{
+ struct nouveau_drm *drm = nouveau_drm(dev);
struct nv04_display *disp = nv04_display(dev);
struct drm_encoder *encoder;
struct drm_crtc *crtc;
+ NV_DEBUG(drm, "\n");
+
/* Turn every CRTC off. */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct drm_mode_set modeset = {
diff --git a/trunk/drivers/gpu/drm/nouveau/nv10_fence.c b/trunk/drivers/gpu/drm/nouveau/nv10_fence.c
index 7ae7f97a6d4d..ce752bf5cc4e 100644
--- a/trunk/drivers/gpu/drm/nouveau/nv10_fence.c
+++ b/trunk/drivers/gpu/drm/nouveau/nv10_fence.c
@@ -155,8 +155,6 @@ nv10_fence_destroy(struct nouveau_drm *drm)
{
struct nv10_fence_priv *priv = drm->fence;
nouveau_bo_unmap(priv->bo);
- if (priv->bo)
- nouveau_bo_unpin(priv->bo);
nouveau_bo_ref(NULL, &priv->bo);
drm->fence = NULL;
kfree(priv);
@@ -185,11 +183,8 @@ nv10_fence_create(struct nouveau_drm *drm)
0, 0x0000, NULL, &priv->bo);
if (!ret) {
ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
- if (!ret) {
+ if (!ret)
ret = nouveau_bo_map(priv->bo);
- if (ret)
- nouveau_bo_unpin(priv->bo);
- }
if (ret)
nouveau_bo_ref(NULL, &priv->bo);
}
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_crtc.c b/trunk/drivers/gpu/drm/nouveau/nv50_crtc.c
new file mode 100644
index 000000000000..222de77d6269
--- /dev/null
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -0,0 +1,764 @@
+/*
+ * Copyright (C) 2008 Maarten Maathuis.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include
+#include
+
+#include "nouveau_reg.h"
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
+#include "nouveau_gem.h"
+#include "nouveau_hw.h"
+#include "nouveau_encoder.h"
+#include "nouveau_crtc.h"
+#include "nouveau_connector.h"
+#include "nv50_display.h"
+
+#include
+
+static void
+nv50_crtc_lut_load(struct drm_crtc *crtc)
+{
+ struct nouveau_drm *drm = nouveau_drm(crtc->dev);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
+ int i;
+
+ NV_DEBUG(drm, "\n");
+
+ for (i = 0; i < 256; i++) {
+ writew(nv_crtc->lut.r[i] >> 2, lut + 8*i + 0);
+ writew(nv_crtc->lut.g[i] >> 2, lut + 8*i + 2);
+ writew(nv_crtc->lut.b[i] >> 2, lut + 8*i + 4);
+ }
+
+ if (nv_crtc->lut.depth == 30) {
+ writew(nv_crtc->lut.r[i - 1] >> 2, lut + 8*i + 0);
+ writew(nv_crtc->lut.g[i - 1] >> 2, lut + 8*i + 2);
+ writew(nv_crtc->lut.b[i - 1] >> 2, lut + 8*i + 4);
+ }
+}
+
+int
+nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
+{
+ struct drm_device *dev = nv_crtc->base.dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ int index = nv_crtc->index, ret;
+
+ NV_DEBUG(drm, "index %d\n", nv_crtc->index);
+ NV_DEBUG(drm, "%s\n", blanked ? "blanked" : "unblanked");
+
+ if (blanked) {
+ nv_crtc->cursor.hide(nv_crtc, false);
+
+ ret = RING_SPACE(evo, nv_device(drm->device)->chipset != 0x50 ? 7 : 5);
+ if (ret) {
+ NV_ERROR(drm, "no space while blanking crtc\n");
+ return ret;
+ }
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, CLUT_MODE), 2);
+ OUT_RING(evo, NV50_EVO_CRTC_CLUT_MODE_BLANK);
+ OUT_RING(evo, 0);
+ if (nv_device(drm->device)->chipset != 0x50) {
+ BEGIN_NV04(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
+ OUT_RING(evo, NV84_EVO_CRTC_CLUT_DMA_HANDLE_NONE);
+ }
+
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1);
+ OUT_RING(evo, NV50_EVO_CRTC_FB_DMA_HANDLE_NONE);
+ } else {
+ if (nv_crtc->cursor.visible)
+ nv_crtc->cursor.show(nv_crtc, false);
+ else
+ nv_crtc->cursor.hide(nv_crtc, false);
+
+ ret = RING_SPACE(evo, nv_device(drm->device)->chipset != 0x50 ? 10 : 8);
+ if (ret) {
+ NV_ERROR(drm, "no space while unblanking crtc\n");
+ return ret;
+ }
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, CLUT_MODE), 2);
+ 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.offset >> 8);
+ if (nv_device(drm->device)->chipset != 0x50) {
+ BEGIN_NV04(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
+ OUT_RING(evo, NvEvoVRAM);
+ }
+
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, FB_OFFSET), 2);
+ OUT_RING(evo, nv_crtc->fb.offset >> 8);
+ OUT_RING(evo, 0);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1);
+ if (nv_device(drm->device)->chipset != 0x50)
+ if (nv_crtc->fb.tile_flags == 0x7a00 ||
+ nv_crtc->fb.tile_flags == 0xfe00)
+ OUT_RING(evo, NvEvoFB32);
+ else
+ if (nv_crtc->fb.tile_flags == 0x7000)
+ OUT_RING(evo, NvEvoFB16);
+ else
+ OUT_RING(evo, NvEvoVRAM_LP);
+ else
+ OUT_RING(evo, NvEvoVRAM_LP);
+ }
+
+ nv_crtc->fb.blanked = blanked;
+ return 0;
+}
+
+static int
+nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
+{
+ struct nouveau_channel *evo = nv50_display(nv_crtc->base.dev)->master;
+ struct nouveau_connector *nv_connector;
+ struct drm_connector *connector;
+ int head = nv_crtc->index, ret;
+ u32 mode = 0x00;
+
+ nv_connector = nouveau_crtc_connector_get(nv_crtc);
+ connector = &nv_connector->base;
+ if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
+ if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
+ mode = DITHERING_MODE_DYNAMIC2X2;
+ } else {
+ mode = nv_connector->dithering_mode;
+ }
+
+ if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) {
+ if (connector->display_info.bpc >= 8)
+ mode |= DITHERING_DEPTH_8BPC;
+ } else {
+ mode |= nv_connector->dithering_depth;
+ }
+
+ ret = RING_SPACE(evo, 2 + (update ? 2 : 0));
+ if (ret == 0) {
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(head, DITHER_CTRL), 1);
+ OUT_RING (evo, mode);
+ if (update) {
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING (evo, 0);
+ FIRE_RING (evo);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
+{
+ struct drm_device *dev = nv_crtc->base.dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ int ret;
+ int adj;
+ u32 hue, vib;
+
+ NV_DEBUG(drm, "vibrance = %i, hue = %i\n",
+ nv_crtc->color_vibrance, nv_crtc->vibrant_hue);
+
+ ret = RING_SPACE(evo, 2 + (update ? 2 : 0));
+ if (ret) {
+ NV_ERROR(drm, "no space while setting color vibrance\n");
+ return ret;
+ }
+
+ adj = (nv_crtc->color_vibrance > 0) ? 50 : 0;
+ vib = ((nv_crtc->color_vibrance * 2047 + adj) / 100) & 0xfff;
+
+ hue = ((nv_crtc->vibrant_hue * 2047) / 100) & 0xfff;
+
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1);
+ OUT_RING (evo, (hue << 20) | (vib << 8));
+
+ if (update) {
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING (evo, 0);
+ FIRE_RING (evo);
+ }
+
+ return 0;
+}
+
+struct nouveau_connector *
+nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
+{
+ struct drm_device *dev = nv_crtc->base.dev;
+ struct drm_connector *connector;
+ struct drm_crtc *crtc = to_drm_crtc(nv_crtc);
+
+ /* The safest approach is to find an encoder with the right crtc, that
+ * is also linked to a connector. */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (connector->encoder)
+ if (connector->encoder->crtc == crtc)
+ return nouveau_connector(connector);
+ }
+
+ return NULL;
+}
+
+static int
+nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
+{
+ struct nouveau_connector *nv_connector;
+ struct drm_crtc *crtc = &nv_crtc->base;
+ struct drm_device *dev = crtc->dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ struct drm_display_mode *umode = &crtc->mode;
+ struct drm_display_mode *omode;
+ int scaling_mode, ret;
+ u32 ctrl = 0, oX, oY;
+
+ NV_DEBUG(drm, "\n");
+
+ nv_connector = nouveau_crtc_connector_get(nv_crtc);
+ if (!nv_connector || !nv_connector->native_mode) {
+ NV_ERROR(drm, "no native mode, forcing panel scaling\n");
+ scaling_mode = DRM_MODE_SCALE_NONE;
+ } else {
+ scaling_mode = nv_connector->scaling_mode;
+ }
+
+ /* start off at the resolution we programmed the crtc for, this
+ * effectively handles NONE/FULL scaling
+ */
+ if (scaling_mode != DRM_MODE_SCALE_NONE)
+ omode = nv_connector->native_mode;
+ else
+ omode = umode;
+
+ oX = omode->hdisplay;
+ oY = omode->vdisplay;
+ if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
+ oY *= 2;
+
+ /* add overscan compensation if necessary, will keep the aspect
+ * ratio the same as the backend mode unless overridden by the
+ * user setting both hborder and vborder properties.
+ */
+ if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
+ (nv_connector->underscan == UNDERSCAN_AUTO &&
+ nv_connector->edid &&
+ drm_detect_hdmi_monitor(nv_connector->edid)))) {
+ u32 bX = nv_connector->underscan_hborder;
+ u32 bY = nv_connector->underscan_vborder;
+ u32 aspect = (oY << 19) / oX;
+
+ if (bX) {
+ oX -= (bX * 2);
+ if (bY) oY -= (bY * 2);
+ else oY = ((oX * aspect) + (aspect / 2)) >> 19;
+ } else {
+ oX -= (oX >> 4) + 32;
+ if (bY) oY -= (bY * 2);
+ else oY = ((oX * aspect) + (aspect / 2)) >> 19;
+ }
+ }
+
+ /* handle CENTER/ASPECT scaling, taking into account the areas
+ * removed already for overscan compensation
+ */
+ switch (scaling_mode) {
+ case DRM_MODE_SCALE_CENTER:
+ oX = min((u32)umode->hdisplay, oX);
+ oY = min((u32)umode->vdisplay, oY);
+ /* fall-through */
+ case DRM_MODE_SCALE_ASPECT:
+ if (oY < oX) {
+ u32 aspect = (umode->hdisplay << 19) / umode->vdisplay;
+ oX = ((oY * aspect) + (aspect / 2)) >> 19;
+ } else {
+ u32 aspect = (umode->vdisplay << 19) / umode->hdisplay;
+ oY = ((oX * aspect) + (aspect / 2)) >> 19;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (umode->hdisplay != oX || umode->vdisplay != oY ||
+ umode->flags & DRM_MODE_FLAG_INTERLACE ||
+ umode->flags & DRM_MODE_FLAG_DBLSCAN)
+ ctrl |= NV50_EVO_CRTC_SCALE_CTRL_ACTIVE;
+
+ ret = RING_SPACE(evo, 5);
+ if (ret)
+ return ret;
+
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_CTRL), 1);
+ OUT_RING (evo, ctrl);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_RES1), 2);
+ OUT_RING (evo, oY << 16 | oX);
+ OUT_RING (evo, oY << 16 | oX);
+
+ if (update) {
+ nv50_display_flip_stop(crtc);
+ nv50_display_sync(dev);
+ nv50_display_flip_next(crtc, crtc->fb, NULL);
+ }
+
+ return 0;
+}
+
+int
+nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_clock *clk = nouveau_clock(device);
+
+ return clk->pll_set(clk, PLL_VPLL0 + head, pclk);
+}
+
+static void
+nv50_crtc_destroy(struct drm_crtc *crtc)
+{
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ struct nouveau_drm *drm = nouveau_drm(crtc->dev);
+
+ NV_DEBUG(drm, "\n");
+
+ nouveau_bo_unmap(nv_crtc->lut.nvbo);
+ nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
+ nouveau_bo_unmap(nv_crtc->cursor.nvbo);
+ nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
+ drm_crtc_cleanup(&nv_crtc->base);
+ kfree(nv_crtc);
+}
+
+int
+nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
+ uint32_t buffer_handle, uint32_t width, uint32_t height)
+{
+ struct drm_device *dev = crtc->dev;
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ struct nouveau_bo *cursor = NULL;
+ struct drm_gem_object *gem;
+ int ret = 0, i;
+
+ if (!buffer_handle) {
+ nv_crtc->cursor.hide(nv_crtc, true);
+ return 0;
+ }
+
+ if (width != 64 || height != 64)
+ return -EINVAL;
+
+ gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
+ if (!gem)
+ return -ENOENT;
+ cursor = nouveau_gem_object(gem);
+
+ ret = nouveau_bo_map(cursor);
+ if (ret)
+ goto out;
+
+ /* The simple will do for now. */
+ for (i = 0; i < 64 * 64; i++)
+ nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, nouveau_bo_rd32(cursor, i));
+
+ nouveau_bo_unmap(cursor);
+
+ nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset);
+ nv_crtc->cursor.show(nv_crtc, true);
+
+out:
+ drm_gem_object_unreference_unlocked(gem);
+ return ret;
+}
+
+int
+nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+
+ nv_crtc->cursor.set_pos(nv_crtc, x, y);
+ return 0;
+}
+
+static void
+nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
+ uint32_t start, uint32_t size)
+{
+ int end = (start + size > 256) ? 256 : start + size, i;
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+
+ 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];
+ }
+
+ /* We need to know the depth before we upload, but it's possible to
+ * get called before a framebuffer is bound. If this is the case,
+ * mark the lut values as dirty by setting depth==0, and it'll be
+ * uploaded on the first mode_set_base()
+ */
+ if (!nv_crtc->base.fb) {
+ nv_crtc->lut.depth = 0;
+ return;
+ }
+
+ nv50_crtc_lut_load(crtc);
+}
+
+static void
+nv50_crtc_save(struct drm_crtc *crtc)
+{
+ struct nouveau_drm *drm = nouveau_drm(crtc->dev);
+ NV_ERROR(drm, "!!\n");
+}
+
+static void
+nv50_crtc_restore(struct drm_crtc *crtc)
+{
+ struct nouveau_drm *drm = nouveau_drm(crtc->dev);
+ NV_ERROR(drm, "!!\n");
+}
+
+static const struct drm_crtc_funcs nv50_crtc_funcs = {
+ .save = nv50_crtc_save,
+ .restore = nv50_crtc_restore,
+ .cursor_set = nv50_crtc_cursor_set,
+ .cursor_move = nv50_crtc_cursor_move,
+ .gamma_set = nv50_crtc_gamma_set,
+ .set_config = drm_crtc_helper_set_config,
+ .page_flip = nouveau_crtc_page_flip,
+ .destroy = nv50_crtc_destroy,
+};
+
+static void
+nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+}
+
+static void
+nv50_crtc_prepare(struct drm_crtc *crtc)
+{
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+
+ NV_DEBUG(drm, "index %d\n", nv_crtc->index);
+
+ nv50_display_flip_stop(crtc);
+ drm_vblank_pre_modeset(dev, nv_crtc->index);
+ nv50_crtc_blank(nv_crtc, true);
+}
+
+static void
+nv50_crtc_commit(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+
+ NV_DEBUG(drm, "index %d\n", nv_crtc->index);
+
+ nv50_crtc_blank(nv_crtc, false);
+ drm_vblank_post_modeset(dev, nv_crtc->index);
+ nv50_display_sync(dev);
+ nv50_display_flip_next(crtc, crtc->fb, NULL);
+}
+
+static bool
+nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static int
+nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *passed_fb,
+ int x, int y, bool atomic)
+{
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ struct drm_device *dev = nv_crtc->base.dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ struct drm_framebuffer *drm_fb;
+ struct nouveau_framebuffer *fb;
+ int ret;
+
+ NV_DEBUG(drm, "index %d\n", nv_crtc->index);
+
+ /* no fb bound */
+ if (!atomic && !crtc->fb) {
+ NV_DEBUG(drm, "No FB bound\n");
+ return 0;
+ }
+
+ /* If atomic, we want to switch to the fb we were passed, so
+ * now we update pointers to do that. (We don't pin; just
+ * assume we're already pinned and update the base address.)
+ */
+ if (atomic) {
+ drm_fb = passed_fb;
+ fb = nouveau_framebuffer(passed_fb);
+ } else {
+ drm_fb = crtc->fb;
+ fb = nouveau_framebuffer(crtc->fb);
+ /* If not atomic, we can go ahead and pin, and unpin the
+ * old fb we were passed.
+ */
+ ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
+ if (ret)
+ return ret;
+
+ if (passed_fb) {
+ struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
+ nouveau_bo_unpin(ofb->nvbo);
+ }
+ }
+
+ 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 && nv_device(drm->device)->chipset != 0x50) {
+ ret = RING_SPACE(evo, 2);
+ if (ret)
+ return ret;
+
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_DMA), 1);
+ OUT_RING (evo, fb->r_dma);
+ }
+
+ ret = RING_SPACE(evo, 12);
+ if (ret)
+ return ret;
+
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_OFFSET), 5);
+ OUT_RING (evo, nv_crtc->fb.offset >> 8);
+ OUT_RING (evo, 0);
+ OUT_RING (evo, (drm_fb->height << 16) | drm_fb->width);
+ OUT_RING (evo, fb->r_pitch);
+ OUT_RING (evo, fb->r_format);
+
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CLUT_MODE), 1);
+ OUT_RING (evo, fb->base.depth == 8 ?
+ NV50_EVO_CRTC_CLUT_MODE_OFF : NV50_EVO_CRTC_CLUT_MODE_ON);
+
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_POS), 1);
+ OUT_RING (evo, (y << 16) | x);
+
+ if (nv_crtc->lut.depth != fb->base.depth) {
+ nv_crtc->lut.depth = fb->base.depth;
+ nv50_crtc_lut_load(crtc);
+ }
+
+ return 0;
+}
+
+static int
+nv50_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 drm_device *dev = crtc->dev;
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ u32 head = nv_crtc->index * 0x400;
+ u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
+ u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
+ u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
+ u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
+ u32 vblan2e = 0, vblan2s = 1;
+ int ret;
+
+ /* hw timing description looks like this:
+ *
+ * <---------display--------->
+ * ______
+ * |____________|---------------------------|____________|
+ *
+ * ^ synce ^ blanke ^ blanks ^ active
+ *
+ * interlaced modes also have 2 additional values pointing at the end
+ * and start of the next field's blanking period.
+ */
+
+ hactive = mode->htotal;
+ hsynce = mode->hsync_end - mode->hsync_start - 1;
+ hbackp = mode->htotal - mode->hsync_end;
+ hblanke = hsynce + hbackp;
+ hfrontp = mode->hsync_start - mode->hdisplay;
+ hblanks = mode->htotal - hfrontp - 1;
+
+ vactive = mode->vtotal * vscan / ilace;
+ vsynce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
+ vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
+ vblanke = vsynce + vbackp;
+ vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
+ vblanks = vactive - vfrontp - 1;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ vblan2e = vactive + vsynce + vbackp;
+ vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
+ vactive = (vactive * 2) + 1;
+ }
+
+ ret = RING_SPACE(evo, 18);
+ if (ret == 0) {
+ BEGIN_NV04(evo, 0, 0x0804 + head, 2);
+ OUT_RING (evo, 0x00800000 | mode->clock);
+ OUT_RING (evo, (ilace == 2) ? 2 : 0);
+ BEGIN_NV04(evo, 0, 0x0810 + head, 6);
+ OUT_RING (evo, 0x00000000); /* border colour */
+ OUT_RING (evo, (vactive << 16) | hactive);
+ OUT_RING (evo, ( vsynce << 16) | hsynce);
+ OUT_RING (evo, (vblanke << 16) | hblanke);
+ OUT_RING (evo, (vblanks << 16) | hblanks);
+ OUT_RING (evo, (vblan2e << 16) | vblan2s);
+ BEGIN_NV04(evo, 0, 0x082c + head, 1);
+ OUT_RING (evo, 0x00000000);
+ BEGIN_NV04(evo, 0, 0x0900 + head, 1);
+ OUT_RING (evo, 0x00000311); /* makes sync channel work */
+ BEGIN_NV04(evo, 0, 0x08c8 + head, 1);
+ OUT_RING (evo, (umode->vdisplay << 16) | umode->hdisplay);
+ BEGIN_NV04(evo, 0, 0x08d4 + head, 1);
+ OUT_RING (evo, 0x00000000); /* screen position */
+ }
+
+ nv_crtc->set_dither(nv_crtc, false);
+ nv_crtc->set_scale(nv_crtc, false);
+ nv_crtc->set_color_vibrance(nv_crtc, false);
+
+ return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
+}
+
+static int
+nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ int ret;
+
+ nv50_display_flip_stop(crtc);
+ ret = nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
+ if (ret)
+ return ret;
+
+ ret = nv50_display_sync(crtc->dev);
+ if (ret)
+ return ret;
+
+ return nv50_display_flip_next(crtc, crtc->fb, NULL);
+}
+
+static int
+nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, enum mode_set_atomic state)
+{
+ int ret;
+
+ nv50_display_flip_stop(crtc);
+ ret = nv50_crtc_do_mode_set_base(crtc, fb, x, y, true);
+ if (ret)
+ return ret;
+
+ return nv50_display_sync(crtc->dev);
+}
+
+static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = {
+ .dpms = nv50_crtc_dpms,
+ .prepare = nv50_crtc_prepare,
+ .commit = nv50_crtc_commit,
+ .mode_fixup = nv50_crtc_mode_fixup,
+ .mode_set = nv50_crtc_mode_set,
+ .mode_set_base = nv50_crtc_mode_set_base,
+ .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
+ .load_lut = nv50_crtc_lut_load,
+};
+
+int
+nv50_crtc_create(struct drm_device *dev, int index)
+{
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_crtc *nv_crtc = NULL;
+ int ret, i;
+
+ NV_DEBUG(drm, "\n");
+
+ nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
+ if (!nv_crtc)
+ return -ENOMEM;
+
+ nv_crtc->index = index;
+ nv_crtc->set_dither = nv50_crtc_set_dither;
+ nv_crtc->set_scale = nv50_crtc_set_scale;
+ nv_crtc->set_color_vibrance = nv50_crtc_set_color_vibrance;
+ nv_crtc->color_vibrance = 50;
+ nv_crtc->vibrant_hue = 0;
+ nv_crtc->lut.depth = 0;
+ 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;
+ }
+
+ drm_crtc_init(dev, &nv_crtc->base, &nv50_crtc_funcs);
+ 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, 4096, 0x100, TTM_PL_FLAG_VRAM,
+ 0, 0x0000, NULL, &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;
+
+
+ ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM,
+ 0, 0x0000, NULL, &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;
+
+ nv50_cursor_init(nv_crtc);
+out:
+ if (ret)
+ nv50_crtc_destroy(&nv_crtc->base);
+ return ret;
+}
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_cursor.c b/trunk/drivers/gpu/drm/nouveau/nv50_cursor.c
new file mode 100644
index 000000000000..223da113ceee
--- /dev/null
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_cursor.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008 Maarten Maathuis.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include
+
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
+#include "nouveau_crtc.h"
+#include "nv50_display.h"
+
+static void
+nv50_cursor_show(struct nouveau_crtc *nv_crtc, bool update)
+{
+ struct drm_device *dev = nv_crtc->base.dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ int ret;
+
+ NV_DEBUG(drm, "\n");
+
+ if (update && nv_crtc->cursor.visible)
+ return;
+
+ ret = RING_SPACE(evo, (nv_device(drm->device)->chipset != 0x50 ? 5 : 3) + update * 2);
+ if (ret) {
+ NV_ERROR(drm, "no space while unhiding cursor\n");
+ return;
+ }
+
+ if (nv_device(drm->device)->chipset != 0x50) {
+ BEGIN_NV04(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1);
+ OUT_RING(evo, NvEvoVRAM);
+ }
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CURSOR_CTRL), 2);
+ OUT_RING(evo, NV50_EVO_CRTC_CURSOR_CTRL_SHOW);
+ OUT_RING(evo, nv_crtc->cursor.offset >> 8);
+
+ if (update) {
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING(evo, 0);
+ FIRE_RING(evo);
+ nv_crtc->cursor.visible = true;
+ }
+}
+
+static void
+nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update)
+{
+ struct drm_device *dev = nv_crtc->base.dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ int ret;
+
+ NV_DEBUG(drm, "\n");
+
+ if (update && !nv_crtc->cursor.visible)
+ return;
+
+ ret = RING_SPACE(evo, (nv_device(drm->device)->chipset != 0x50 ? 5 : 3) + update * 2);
+ if (ret) {
+ NV_ERROR(drm, "no space while hiding cursor\n");
+ return;
+ }
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CURSOR_CTRL), 2);
+ OUT_RING(evo, NV50_EVO_CRTC_CURSOR_CTRL_HIDE);
+ OUT_RING(evo, 0);
+ if (nv_device(drm->device)->chipset != 0x50) {
+ BEGIN_NV04(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1);
+ OUT_RING(evo, NV84_EVO_CRTC_CURSOR_DMA_HANDLE_NONE);
+ }
+
+ if (update) {
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING(evo, 0);
+ FIRE_RING(evo);
+ nv_crtc->cursor.visible = false;
+ }
+}
+
+static void
+nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
+{
+ struct nouveau_device *device = nouveau_dev(nv_crtc->base.dev);
+
+ nv_crtc->cursor_saved_x = x; nv_crtc->cursor_saved_y = y;
+ nv_wr32(device, NV50_PDISPLAY_CURSOR_USER_POS(nv_crtc->index),
+ ((y & 0xFFFF) << 16) | (x & 0xFFFF));
+ /* Needed to make the cursor move. */
+ nv_wr32(device, NV50_PDISPLAY_CURSOR_USER_POS_CTRL(nv_crtc->index), 0);
+}
+
+static void
+nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
+{
+ if (offset == nv_crtc->cursor.offset)
+ return;
+
+ nv_crtc->cursor.offset = offset;
+ if (nv_crtc->cursor.visible) {
+ nv_crtc->cursor.visible = false;
+ nv_crtc->cursor.show(nv_crtc, true);
+ }
+}
+
+int
+nv50_cursor_init(struct nouveau_crtc *nv_crtc)
+{
+ nv_crtc->cursor.set_offset = nv50_cursor_set_offset;
+ nv_crtc->cursor.set_pos = nv50_cursor_set_pos;
+ nv_crtc->cursor.hide = nv50_cursor_hide;
+ nv_crtc->cursor.show = nv50_cursor_show;
+ return 0;
+}
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_dac.c b/trunk/drivers/gpu/drm/nouveau/nv50_dac.c
new file mode 100644
index 000000000000..6a30a1748573
--- /dev/null
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2008 Maarten Maathuis.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include
+#include
+
+#define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
+#include "nouveau_reg.h"
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
+#include "nouveau_encoder.h"
+#include "nouveau_connector.h"
+#include "nouveau_crtc.h"
+#include "nv50_display.h"
+
+#include
+
+static void
+nv50_dac_disconnect(struct drm_encoder *encoder)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct drm_device *dev = encoder->dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ int ret;
+
+ if (!nv_encoder->crtc)
+ return;
+ nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
+
+ NV_DEBUG(drm, "Disconnecting DAC %d\n", nv_encoder->or);
+
+ ret = RING_SPACE(evo, 4);
+ if (ret) {
+ NV_ERROR(drm, "no space while disconnecting DAC\n");
+ return;
+ }
+ BEGIN_NV04(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
+ OUT_RING (evo, 0);
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING (evo, 0);
+
+ nv_encoder->crtc = NULL;
+}
+
+static enum drm_connector_status
+nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_device *device = nouveau_dev(encoder->dev);
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ enum drm_connector_status status = connector_status_disconnected;
+ uint32_t dpms_state, load_pattern, load_state;
+ int or = nv_encoder->or;
+
+ nv_wr32(device, NV50_PDISPLAY_DAC_CLK_CTRL1(or), 0x00000001);
+ dpms_state = nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or));
+
+ nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+ 0x00150000 | NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
+ if (!nv_wait(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+ NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
+ NV_ERROR(drm, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
+ NV_ERROR(drm, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
+ nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or)));
+ return status;
+ }
+
+ /* Use bios provided value if possible. */
+ if (drm->vbios.dactestval) {
+ load_pattern = drm->vbios.dactestval;
+ NV_DEBUG(drm, "Using bios provided load_pattern of %d\n",
+ load_pattern);
+ } else {
+ load_pattern = 340;
+ NV_DEBUG(drm, "Using default load_pattern of %d\n",
+ load_pattern);
+ }
+
+ nv_wr32(device, NV50_PDISPLAY_DAC_LOAD_CTRL(or),
+ NV50_PDISPLAY_DAC_LOAD_CTRL_ACTIVE | load_pattern);
+ mdelay(45); /* give it some time to process */
+ load_state = nv_rd32(device, NV50_PDISPLAY_DAC_LOAD_CTRL(or));
+
+ nv_wr32(device, NV50_PDISPLAY_DAC_LOAD_CTRL(or), 0);
+ nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or), dpms_state |
+ NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
+
+ if ((load_state & NV50_PDISPLAY_DAC_LOAD_CTRL_PRESENT) ==
+ NV50_PDISPLAY_DAC_LOAD_CTRL_PRESENT)
+ status = connector_status_connected;
+
+ if (status == connector_status_connected)
+ NV_DEBUG(drm, "Load was detected on output with or %d\n", or);
+ else
+ NV_DEBUG(drm, "Load was not detected on output with or %d\n", or);
+
+ return status;
+}
+
+static void
+nv50_dac_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct nouveau_device *device = nouveau_dev(encoder->dev);
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ uint32_t val;
+ int or = nv_encoder->or;
+
+ NV_DEBUG(drm, "or %d mode %d\n", or, mode);
+
+ /* wait for it to be done */
+ if (!nv_wait(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+ NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
+ NV_ERROR(drm, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
+ NV_ERROR(drm, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
+ nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or)));
+ return;
+ }
+
+ val = nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or)) & ~0x7F;
+
+ if (mode != DRM_MODE_DPMS_ON)
+ val |= NV50_PDISPLAY_DAC_DPMS_CTRL_BLANKED;
+
+ switch (mode) {
+ case DRM_MODE_DPMS_STANDBY:
+ val |= NV50_PDISPLAY_DAC_DPMS_CTRL_HSYNC_OFF;
+ break;
+ case DRM_MODE_DPMS_SUSPEND:
+ val |= NV50_PDISPLAY_DAC_DPMS_CTRL_VSYNC_OFF;
+ break;
+ case DRM_MODE_DPMS_OFF:
+ val |= NV50_PDISPLAY_DAC_DPMS_CTRL_OFF;
+ val |= NV50_PDISPLAY_DAC_DPMS_CTRL_HSYNC_OFF;
+ val |= NV50_PDISPLAY_DAC_DPMS_CTRL_VSYNC_OFF;
+ break;
+ default:
+ break;
+ }
+
+ nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or), val |
+ NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
+}
+
+static void
+nv50_dac_save(struct drm_encoder *encoder)
+{
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ NV_ERROR(drm, "!!\n");
+}
+
+static void
+nv50_dac_restore(struct drm_encoder *encoder)
+{
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ NV_ERROR(drm, "!!\n");
+}
+
+static bool
+nv50_dac_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_connector *connector;
+
+ NV_DEBUG(drm, "or %d\n", nv_encoder->or);
+
+ connector = nouveau_encoder_connector_get(nv_encoder);
+ if (!connector) {
+ NV_ERROR(drm, "Encoder has no connector\n");
+ return false;
+ }
+
+ if (connector->scaling_mode != DRM_MODE_SCALE_NONE &&
+ connector->native_mode)
+ drm_mode_copy(adjusted_mode, connector->native_mode);
+
+ return true;
+}
+
+static void
+nv50_dac_commit(struct drm_encoder *encoder)
+{
+}
+
+static void
+nv50_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_drm *drm = nouveau_drm(encoder->dev);
+ struct drm_device *dev = encoder->dev;
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc);
+ uint32_t mode_ctl = 0, mode_ctl2 = 0;
+ int ret;
+
+ NV_DEBUG(drm, "or %d type %d crtc %d\n",
+ nv_encoder->or, nv_encoder->dcb->type, crtc->index);
+
+ nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
+
+ if (crtc->index == 1)
+ mode_ctl |= NV50_EVO_DAC_MODE_CTRL_CRTC1;
+ else
+ mode_ctl |= NV50_EVO_DAC_MODE_CTRL_CRTC0;
+
+ /* Lacking a working tv-out, this is not a 100% sure. */
+ if (nv_encoder->dcb->type == DCB_OUTPUT_ANALOG)
+ mode_ctl |= 0x40;
+ else
+ if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
+ mode_ctl |= 0x100;
+
+ if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+ mode_ctl2 |= NV50_EVO_DAC_MODE_CTRL2_NHSYNC;
+
+ if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+ mode_ctl2 |= NV50_EVO_DAC_MODE_CTRL2_NVSYNC;
+
+ ret = RING_SPACE(evo, 3);
+ if (ret) {
+ NV_ERROR(drm, "no space while connecting DAC\n");
+ return;
+ }
+ BEGIN_NV04(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
+ OUT_RING(evo, mode_ctl);
+ OUT_RING(evo, mode_ctl2);
+
+ nv_encoder->crtc = encoder->crtc;
+}
+
+static struct drm_crtc *
+nv50_dac_crtc_get(struct drm_encoder *encoder)
+{
+ return nouveau_encoder(encoder)->crtc;
+}
+
+static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
+ .dpms = nv50_dac_dpms,
+ .save = nv50_dac_save,
+ .restore = nv50_dac_restore,
+ .mode_fixup = nv50_dac_mode_fixup,
+ .prepare = nv50_dac_disconnect,
+ .commit = nv50_dac_commit,
+ .mode_set = nv50_dac_mode_set,
+ .get_crtc = nv50_dac_crtc_get,
+ .detect = nv50_dac_detect,
+ .disable = nv50_dac_disconnect
+};
+
+static void
+nv50_dac_destroy(struct drm_encoder *encoder)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+
+ if (!encoder)
+ return;
+
+ NV_DEBUG(drm, "\n");
+
+ drm_encoder_cleanup(encoder);
+ kfree(nv_encoder);
+}
+
+static const struct drm_encoder_funcs nv50_dac_encoder_funcs = {
+ .destroy = nv50_dac_destroy,
+};
+
+int
+nv50_dac_create(struct drm_connector *connector, struct dcb_output *entry)
+{
+ struct nouveau_encoder *nv_encoder;
+ struct drm_encoder *encoder;
+
+ nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
+ if (!nv_encoder)
+ return -ENOMEM;
+ encoder = to_drm_encoder(nv_encoder);
+
+ nv_encoder->dcb = entry;
+ nv_encoder->or = ffs(entry->or) - 1;
+
+ drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
+ DRM_MODE_ENCODER_DAC);
+ drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
+
+ encoder->possible_crtcs = entry->heads;
+ encoder->possible_clones = 0;
+
+ drm_mode_connector_attach_encoder(connector, encoder);
+ return 0;
+}
+
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_display.c b/trunk/drivers/gpu/drm/nouveau/nv50_display.c
index 35874085a61e..f97b42cbb6bb 100644
--- a/trunk/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_display.c
@@ -1,2058 +1,969 @@
- /*
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright (C) 2008 Maarten Maathuis.
+ * All Rights Reserved.
*
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
+ * 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 above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
*
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: Ben Skeggs
*/
-#include
-
-#include
-#include
-
#include "nouveau_drm.h"
#include "nouveau_dma.h"
-#include "nouveau_gem.h"
-#include "nouveau_connector.h"
-#include "nouveau_encoder.h"
+
+#include "nv50_display.h"
#include "nouveau_crtc.h"
+#include "nouveau_encoder.h"
+#include "nouveau_connector.h"
+#include "nouveau_fbcon.h"
+#include
#include "nouveau_fence.h"
-#include "nv50_display.h"
-#include
#include
-#include
-
#include
-#include
-#include
-
-#define EVO_DMA_NR 9
-
-#define EVO_MASTER (0x00)
-#define EVO_FLIP(c) (0x01 + (c))
-#define EVO_OVLY(c) (0x05 + (c))
-#define EVO_OIMM(c) (0x09 + (c))
-#define EVO_CURS(c) (0x0d + (c))
-
-/* offsets in shared sync bo of various structures */
-#define EVO_SYNC(c, o) ((c) * 0x0100 + (o))
-#define EVO_MAST_NTFY EVO_SYNC( 0, 0x00)
-#define EVO_FLIP_SEM0(c) EVO_SYNC((c), 0x00)
-#define EVO_FLIP_SEM1(c) EVO_SYNC((c), 0x10)
-
-#define EVO_CORE_HANDLE (0xd1500000)
-#define EVO_CHAN_HANDLE(t,i) (0xd15c0000 | (((t) & 0x00ff) << 8) | (i))
-#define EVO_CHAN_OCLASS(t,c) ((nv_hclass(c) & 0xff00) | ((t) & 0x00ff))
-#define EVO_PUSH_HANDLE(t,i) (0xd15b0000 | (i) | \
- (((NV50_DISP_##t##_CLASS) & 0x00ff) << 8))
-
-/******************************************************************************
- * EVO channel
- *****************************************************************************/
-
-struct nv50_chan {
- struct nouveau_object *user;
- u32 handle;
-};
-
-static int
-nv50_chan_create(struct nouveau_object *core, u32 bclass, u8 head,
- void *data, u32 size, struct nv50_chan *chan)
+
+static void nv50_display_bh(unsigned long);
+
+static inline int
+nv50_sor_nr(struct drm_device *dev)
{
- struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
- const u32 oclass = EVO_CHAN_OCLASS(bclass, core);
- const u32 handle = EVO_CHAN_HANDLE(bclass, head);
- int ret;
+ struct nouveau_device *device = nouveau_dev(dev);
- ret = nouveau_object_new(client, EVO_CORE_HANDLE, handle,
- oclass, data, size, &chan->user);
- if (ret)
- return ret;
+ if (device->chipset < 0x90 ||
+ device->chipset == 0x92 ||
+ device->chipset == 0xa0)
+ return 2;
- chan->handle = handle;
- return 0;
+ return 4;
}
-static void
-nv50_chan_destroy(struct nouveau_object *core, struct nv50_chan *chan)
+u32
+nv50_display_active_crtcs(struct drm_device *dev)
{
- struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
- if (chan->handle)
- nouveau_object_del(client, EVO_CORE_HANDLE, chan->handle);
-}
+ struct nouveau_device *device = nouveau_dev(dev);
+ u32 mask = 0;
+ int i;
-/******************************************************************************
- * PIO EVO channel
- *****************************************************************************/
+ if (device->chipset < 0x90 ||
+ device->chipset == 0x92 ||
+ device->chipset == 0xa0) {
+ for (i = 0; i < 2; i++)
+ mask |= nv_rd32(device, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
+ } else {
+ for (i = 0; i < 4; i++)
+ mask |= nv_rd32(device, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
+ }
-struct nv50_pioc {
- struct nv50_chan base;
-};
+ for (i = 0; i < 3; i++)
+ mask |= nv_rd32(device, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
-static void
-nv50_pioc_destroy(struct nouveau_object *core, struct nv50_pioc *pioc)
+ return mask & 3;
+}
+
+int
+nv50_display_early_init(struct drm_device *dev)
{
- nv50_chan_destroy(core, &pioc->base);
+ return 0;
}
-static int
-nv50_pioc_create(struct nouveau_object *core, u32 bclass, u8 head,
- void *data, u32 size, struct nv50_pioc *pioc)
+void
+nv50_display_late_takedown(struct drm_device *dev)
{
- return nv50_chan_create(core, bclass, head, data, size, &pioc->base);
}
-/******************************************************************************
- * DMA EVO channel
- *****************************************************************************/
+int
+nv50_display_sync(struct drm_device *dev)
+{
+ struct nv50_display *disp = nv50_display(dev);
+ struct nouveau_channel *evo = disp->master;
+ int ret;
-struct nv50_dmac {
- struct nv50_chan base;
- dma_addr_t handle;
- u32 *ptr;
-};
+ ret = RING_SPACE(evo, 6);
+ if (ret == 0) {
+ BEGIN_NV04(evo, 0, 0x0084, 1);
+ OUT_RING (evo, 0x80000000);
+ BEGIN_NV04(evo, 0, 0x0080, 1);
+ OUT_RING (evo, 0);
+ BEGIN_NV04(evo, 0, 0x0084, 1);
+ OUT_RING (evo, 0x00000000);
-static void
-nv50_dmac_destroy(struct nouveau_object *core, struct nv50_dmac *dmac)
-{
- if (dmac->ptr) {
- struct pci_dev *pdev = nv_device(core)->pdev;
- pci_free_consistent(pdev, PAGE_SIZE, dmac->ptr, dmac->handle);
+ nv_wo32(disp->ramin, 0x2000, 0x00000000);
+ FIRE_RING (evo);
+
+ if (nv_wait_ne(disp->ramin, 0x2000, 0xffffffff, 0x00000000))
+ return 0;
}
- nv50_chan_destroy(core, &dmac->base);
+ return 0;
}
-static int
-nv50_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
+int
+nv50_display_init(struct drm_device *dev)
{
- struct nouveau_fb *pfb = nouveau_fb(core);
- struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
- struct nouveau_object *object;
- int ret = nouveau_object_new(client, parent, NvEvoVRAM_LP,
- NV_DMA_IN_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_VRAM |
- NV_DMA_ACCESS_RDWR,
- .start = 0,
- .limit = pfb->ram.size - 1,
- .conf0 = NV50_DMA_CONF0_ENABLE |
- NV50_DMA_CONF0_PART_256,
- }, sizeof(struct nv_dma_class), &object);
- if (ret)
- return ret;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_channel *evo;
+ int ret, i;
+ u32 val;
- ret = nouveau_object_new(client, parent, NvEvoFB16,
- NV_DMA_IN_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_VRAM |
- NV_DMA_ACCESS_RDWR,
- .start = 0,
- .limit = pfb->ram.size - 1,
- .conf0 = NV50_DMA_CONF0_ENABLE | 0x70 |
- NV50_DMA_CONF0_PART_256,
- }, sizeof(struct nv_dma_class), &object);
- if (ret)
- return ret;
+ NV_DEBUG(drm, "\n");
- ret = nouveau_object_new(client, parent, NvEvoFB32,
- NV_DMA_IN_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_VRAM |
- NV_DMA_ACCESS_RDWR,
- .start = 0,
- .limit = pfb->ram.size - 1,
- .conf0 = NV50_DMA_CONF0_ENABLE | 0x7a |
- NV50_DMA_CONF0_PART_256,
- }, sizeof(struct nv_dma_class), &object);
- return ret;
-}
+ nv_wr32(device, 0x00610184, nv_rd32(device, 0x00614004));
-static int
-nvc0_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
-{
- struct nouveau_fb *pfb = nouveau_fb(core);
- struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
- struct nouveau_object *object;
- int ret = nouveau_object_new(client, parent, NvEvoVRAM_LP,
- NV_DMA_IN_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_VRAM |
- NV_DMA_ACCESS_RDWR,
- .start = 0,
- .limit = pfb->ram.size - 1,
- .conf0 = NVC0_DMA_CONF0_ENABLE,
- }, sizeof(struct nv_dma_class), &object);
- if (ret)
- return ret;
+ /*
+ * I think the 0x006101XX range is some kind of main control area
+ * that enables things.
+ */
+ /* CRTC? */
+ for (i = 0; i < 2; i++) {
+ val = nv_rd32(device, 0x00616100 + (i * 0x800));
+ nv_wr32(device, 0x00610190 + (i * 0x10), val);
+ val = nv_rd32(device, 0x00616104 + (i * 0x800));
+ nv_wr32(device, 0x00610194 + (i * 0x10), val);
+ val = nv_rd32(device, 0x00616108 + (i * 0x800));
+ nv_wr32(device, 0x00610198 + (i * 0x10), val);
+ val = nv_rd32(device, 0x0061610c + (i * 0x800));
+ nv_wr32(device, 0x0061019c + (i * 0x10), val);
+ }
+
+ /* DAC */
+ for (i = 0; i < 3; i++) {
+ val = nv_rd32(device, 0x0061a000 + (i * 0x800));
+ nv_wr32(device, 0x006101d0 + (i * 0x04), val);
+ }
+
+ /* SOR */
+ for (i = 0; i < nv50_sor_nr(dev); i++) {
+ val = nv_rd32(device, 0x0061c000 + (i * 0x800));
+ nv_wr32(device, 0x006101e0 + (i * 0x04), val);
+ }
+
+ /* EXT */
+ for (i = 0; i < 3; i++) {
+ val = nv_rd32(device, 0x0061e000 + (i * 0x800));
+ nv_wr32(device, 0x006101f0 + (i * 0x04), val);
+ }
+
+ for (i = 0; i < 3; i++) {
+ nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(i), 0x00550000 |
+ NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
+ nv_wr32(device, NV50_PDISPLAY_DAC_CLK_CTRL1(i), 0x00000001);
+ }
- ret = nouveau_object_new(client, parent, NvEvoFB16,
- NV_DMA_IN_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_VRAM |
- NV_DMA_ACCESS_RDWR,
- .start = 0,
- .limit = pfb->ram.size - 1,
- .conf0 = NVC0_DMA_CONF0_ENABLE | 0xfe,
- }, sizeof(struct nv_dma_class), &object);
+ /* The precise purpose is unknown, i suspect it has something to do
+ * with text mode.
+ */
+ if (nv_rd32(device, NV50_PDISPLAY_INTR_1) & 0x100) {
+ nv_wr32(device, NV50_PDISPLAY_INTR_1, 0x100);
+ nv_wr32(device, 0x006194e8, nv_rd32(device, 0x006194e8) & ~1);
+ if (!nv_wait(device, 0x006194e8, 2, 0)) {
+ NV_ERROR(drm, "timeout: (0x6194e8 & 2) != 0\n");
+ NV_ERROR(drm, "0x6194e8 = 0x%08x\n",
+ nv_rd32(device, 0x6194e8));
+ return -EBUSY;
+ }
+ }
+
+ for (i = 0; i < 2; i++) {
+ nv_wr32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000);
+ if (!nv_wait(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+ NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
+ NV_ERROR(drm, "timeout: CURSOR_CTRL2_STATUS == 0\n");
+ NV_ERROR(drm, "CURSOR_CTRL2 = 0x%08x\n",
+ nv_rd32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
+ return -EBUSY;
+ }
+
+ nv_wr32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+ NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON);
+ if (!nv_wait(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+ NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS,
+ NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) {
+ NV_ERROR(drm, "timeout: "
+ "CURSOR_CTRL2_STATUS_ACTIVE(%d)\n", i);
+ NV_ERROR(drm, "CURSOR_CTRL2(%d) = 0x%08x\n", i,
+ nv_rd32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
+ return -EBUSY;
+ }
+ }
+
+ nv_wr32(device, NV50_PDISPLAY_PIO_CTRL, 0x00000000);
+ nv_mask(device, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000);
+ nv_wr32(device, NV50_PDISPLAY_INTR_EN_0, 0x00000000);
+ nv_mask(device, NV50_PDISPLAY_INTR_1, 0x00000000, 0x00000000);
+ nv_wr32(device, NV50_PDISPLAY_INTR_EN_1,
+ NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 |
+ NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 |
+ NV50_PDISPLAY_INTR_EN_1_CLK_UNK40);
+
+ ret = nv50_evo_init(dev);
if (ret)
return ret;
+ evo = nv50_display(dev)->master;
- ret = nouveau_object_new(client, parent, NvEvoFB32,
- NV_DMA_IN_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_VRAM |
- NV_DMA_ACCESS_RDWR,
- .start = 0,
- .limit = pfb->ram.size - 1,
- .conf0 = NVC0_DMA_CONF0_ENABLE | 0xfe,
- }, sizeof(struct nv_dma_class), &object);
- return ret;
-}
+ nv_wr32(device, NV50_PDISPLAY_OBJECTS, (nv50_display(dev)->ramin->addr >> 8) | 9);
-static int
-nvd0_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
-{
- struct nouveau_fb *pfb = nouveau_fb(core);
- struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
- struct nouveau_object *object;
- int ret = nouveau_object_new(client, parent, NvEvoVRAM_LP,
- NV_DMA_IN_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_VRAM |
- NV_DMA_ACCESS_RDWR,
- .start = 0,
- .limit = pfb->ram.size - 1,
- .conf0 = NVD0_DMA_CONF0_ENABLE |
- NVD0_DMA_CONF0_PAGE_LP,
- }, sizeof(struct nv_dma_class), &object);
+ ret = RING_SPACE(evo, 3);
if (ret)
return ret;
+ BEGIN_NV04(evo, 0, NV50_EVO_UNK84, 2);
+ OUT_RING (evo, NV50_EVO_UNK84_NOTIFY_DISABLED);
+ OUT_RING (evo, NvEvoSync);
- ret = nouveau_object_new(client, parent, NvEvoFB32,
- NV_DMA_IN_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_VRAM |
- NV_DMA_ACCESS_RDWR,
- .start = 0,
- .limit = pfb->ram.size - 1,
- .conf0 = NVD0_DMA_CONF0_ENABLE | 0xfe |
- NVD0_DMA_CONF0_PAGE_LP,
- }, sizeof(struct nv_dma_class), &object);
- return ret;
+ return nv50_display_sync(dev);
}
-static int
-nv50_dmac_create(struct nouveau_object *core, u32 bclass, u8 head,
- void *data, u32 size, u64 syncbuf,
- struct nv50_dmac *dmac)
+void
+nv50_display_fini(struct drm_device *dev)
{
- struct nouveau_fb *pfb = nouveau_fb(core);
- struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
- struct nouveau_object *object;
- u32 pushbuf = *(u32 *)data;
- int ret;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nv50_display *disp = nv50_display(dev);
+ struct nouveau_channel *evo = disp->master;
+ struct drm_crtc *drm_crtc;
+ int ret, i;
- dmac->ptr = pci_alloc_consistent(nv_device(core)->pdev, PAGE_SIZE,
- &dmac->handle);
- if (!dmac->ptr)
- return -ENOMEM;
+ NV_DEBUG(drm, "\n");
- ret = nouveau_object_new(client, NVDRM_DEVICE, pushbuf,
- NV_DMA_FROM_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_PCI_US |
- NV_DMA_ACCESS_RD,
- .start = dmac->handle + 0x0000,
- .limit = dmac->handle + 0x0fff,
- }, sizeof(struct nv_dma_class), &object);
- if (ret)
- return ret;
+ list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc);
- ret = nv50_chan_create(core, bclass, head, data, size, &dmac->base);
- if (ret)
- return ret;
+ nv50_crtc_blank(crtc, true);
+ }
- ret = nouveau_object_new(client, dmac->base.handle, NvEvoSync,
- NV_DMA_IN_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_VRAM |
- NV_DMA_ACCESS_RDWR,
- .start = syncbuf + 0x0000,
- .limit = syncbuf + 0x0fff,
- }, sizeof(struct nv_dma_class), &object);
- if (ret)
- return ret;
+ ret = RING_SPACE(evo, 2);
+ if (ret == 0) {
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING(evo, 0);
+ }
+ FIRE_RING(evo);
- ret = nouveau_object_new(client, dmac->base.handle, NvEvoVRAM,
- NV_DMA_IN_MEMORY_CLASS,
- &(struct nv_dma_class) {
- .flags = NV_DMA_TARGET_VRAM |
- NV_DMA_ACCESS_RDWR,
- .start = 0,
- .limit = pfb->ram.size - 1,
- }, sizeof(struct nv_dma_class), &object);
- if (ret)
- return ret;
+ /* Almost like ack'ing a vblank interrupt, maybe in the spirit of
+ * cleaning up?
+ */
+ list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc);
+ uint32_t mask = NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(crtc->index);
- if (nv_device(core)->card_type < NV_C0)
- ret = nv50_dmac_create_fbdma(core, dmac->base.handle);
- else
- if (nv_device(core)->card_type < NV_D0)
- ret = nvc0_dmac_create_fbdma(core, dmac->base.handle);
- else
- ret = nvd0_dmac_create_fbdma(core, dmac->base.handle);
- return ret;
-}
+ if (!crtc->base.enabled)
+ continue;
-struct nv50_mast {
- struct nv50_dmac base;
-};
-
-struct nv50_curs {
- struct nv50_pioc base;
-};
-
-struct nv50_sync {
- struct nv50_dmac base;
- struct {
- u32 offset;
- u16 value;
- } sem;
-};
-
-struct nv50_ovly {
- struct nv50_dmac base;
-};
-
-struct nv50_oimm {
- struct nv50_pioc base;
-};
-
-struct nv50_head {
- struct nouveau_crtc base;
- struct nv50_curs curs;
- struct nv50_sync sync;
- struct nv50_ovly ovly;
- struct nv50_oimm oimm;
-};
-
-#define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c))
-#define nv50_curs(c) (&nv50_head(c)->curs)
-#define nv50_sync(c) (&nv50_head(c)->sync)
-#define nv50_ovly(c) (&nv50_head(c)->ovly)
-#define nv50_oimm(c) (&nv50_head(c)->oimm)
-#define nv50_chan(c) (&(c)->base.base)
-#define nv50_vers(c) nv_mclass(nv50_chan(c)->user)
-
-struct nv50_disp {
- struct nouveau_object *core;
- struct nv50_mast mast;
-
- u32 modeset;
-
- struct nouveau_bo *sync;
-};
-
-static struct nv50_disp *
-nv50_disp(struct drm_device *dev)
-{
- return nouveau_display(dev)->priv;
-}
+ nv_wr32(device, NV50_PDISPLAY_INTR_1, mask);
+ if (!nv_wait(device, NV50_PDISPLAY_INTR_1, mask, mask)) {
+ NV_ERROR(drm, "timeout: (0x610024 & 0x%08x) == "
+ "0x%08x\n", mask, mask);
+ NV_ERROR(drm, "0x610024 = 0x%08x\n",
+ nv_rd32(device, NV50_PDISPLAY_INTR_1));
+ }
+ }
+
+ for (i = 0; i < 2; i++) {
+ nv_wr32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0);
+ if (!nv_wait(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+ NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
+ NV_ERROR(drm, "timeout: CURSOR_CTRL2_STATUS == 0\n");
+ NV_ERROR(drm, "CURSOR_CTRL2 = 0x%08x\n",
+ nv_rd32(device, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
+ }
+ }
-#define nv50_mast(d) (&nv50_disp(d)->mast)
+ nv50_evo_fini(dev);
-static struct drm_crtc *
-nv50_display_crtc_get(struct drm_encoder *encoder)
-{
- return nouveau_encoder(encoder)->crtc;
+ for (i = 0; i < 3; i++) {
+ if (!nv_wait(device, NV50_PDISPLAY_SOR_DPMS_STATE(i),
+ NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
+ NV_ERROR(drm, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i);
+ NV_ERROR(drm, "SOR_DPMS_STATE(%d) = 0x%08x\n", i,
+ nv_rd32(device, NV50_PDISPLAY_SOR_DPMS_STATE(i)));
+ }
+ }
+
+ /* disable interrupts. */
+ nv_wr32(device, NV50_PDISPLAY_INTR_EN_1, 0x00000000);
}
-/******************************************************************************
- * EVO channel helpers
- *****************************************************************************/
-static u32 *
-evo_wait(void *evoc, int nr)
+int
+nv50_display_create(struct drm_device *dev)
{
- struct nv50_dmac *dmac = evoc;
- u32 put = nv_ro32(dmac->base.user, 0x0000) / 4;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct dcb_table *dcb = &drm->vbios.dcb;
+ struct drm_connector *connector, *ct;
+ struct nv50_display *priv;
+ int ret, i;
+
+ NV_DEBUG(drm, "\n");
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ nouveau_display(dev)->priv = priv;
+ nouveau_display(dev)->dtor = nv50_display_destroy;
+ nouveau_display(dev)->init = nv50_display_init;
+ nouveau_display(dev)->fini = nv50_display_fini;
+
+ /* Create CRTC objects */
+ for (i = 0; i < 2; i++) {
+ ret = nv50_crtc_create(dev, i);
+ if (ret)
+ return ret;
+ }
- if (put + nr >= (PAGE_SIZE / 4) - 8) {
- dmac->ptr[put] = 0x20000000;
+ /* We setup the encoders from the BIOS table */
+ for (i = 0 ; i < dcb->entries; i++) {
+ struct dcb_output *entry = &dcb->entry[i];
- nv_wo32(dmac->base.user, 0x0000, 0x00000000);
- if (!nv_wait(dmac->base.user, 0x0004, ~0, 0x00000000)) {
- NV_ERROR(dmac->base.user, "channel stalled\n");
- return NULL;
+ if (entry->location != DCB_LOC_ON_CHIP) {
+ NV_WARN(drm, "Off-chip encoder %d/%d unsupported\n",
+ entry->type, ffs(entry->or) - 1);
+ continue;
}
- put = 0;
+ connector = nouveau_connector_create(dev, entry->connector);
+ if (IS_ERR(connector))
+ continue;
+
+ switch (entry->type) {
+ case DCB_OUTPUT_TMDS:
+ case DCB_OUTPUT_LVDS:
+ case DCB_OUTPUT_DP:
+ nv50_sor_create(connector, entry);
+ break;
+ case DCB_OUTPUT_ANALOG:
+ nv50_dac_create(connector, entry);
+ break;
+ default:
+ NV_WARN(drm, "DCB encoder %d unknown\n", entry->type);
+ continue;
+ }
}
- return dmac->ptr + put;
-}
+ list_for_each_entry_safe(connector, ct,
+ &dev->mode_config.connector_list, head) {
+ if (!connector->encoder_ids[0]) {
+ NV_WARN(drm, "%s has no encoders, removing\n",
+ drm_get_connector_name(connector));
+ connector->funcs->destroy(connector);
+ }
+ }
-static void
-evo_kick(u32 *push, void *evoc)
-{
- struct nv50_dmac *dmac = evoc;
- nv_wo32(dmac->base.user, 0x0000, (push - dmac->ptr) << 2);
-}
+ tasklet_init(&priv->tasklet, nv50_display_bh, (unsigned long)dev);
-#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
-#define evo_data(p,d) *((p)++) = (d)
+ ret = nv50_evo_create(dev);
+ if (ret) {
+ nv50_display_destroy(dev);
+ return ret;
+ }
-static bool
-evo_sync_wait(void *data)
-{
- return nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000;
+ return 0;
}
-static int
-evo_sync(struct drm_device *dev)
+void
+nv50_display_destroy(struct drm_device *dev)
{
- struct nouveau_device *device = nouveau_dev(dev);
- struct nv50_disp *disp = nv50_disp(dev);
- struct nv50_mast *mast = nv50_mast(dev);
- u32 *push = evo_wait(mast, 8);
- if (push) {
- nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000);
- evo_mthd(push, 0x0084, 1);
- evo_data(push, 0x80000000 | EVO_MAST_NTFY);
- evo_mthd(push, 0x0080, 2);
- evo_data(push, 0x00000000);
- evo_data(push, 0x00000000);
- evo_kick(push, mast);
- if (nv_wait_cb(device, evo_sync_wait, disp->sync))
- return 0;
- }
+ struct nv50_display *disp = nv50_display(dev);
- return -EBUSY;
+ nv50_evo_destroy(dev);
+ kfree(disp);
}
-/******************************************************************************
- * Page flipping channel
- *****************************************************************************/
struct nouveau_bo *
nv50_display_crtc_sema(struct drm_device *dev, int crtc)
{
- return nv50_disp(dev)->sync;
+ return nv50_display(dev)->crtc[crtc].sem.bo;
}
void
nv50_display_flip_stop(struct drm_crtc *crtc)
{
- struct nv50_sync *sync = nv50_sync(crtc);
- u32 *push;
-
- push = evo_wait(sync, 8);
- if (push) {
- evo_mthd(push, 0x0084, 1);
- evo_data(push, 0x00000000);
- evo_mthd(push, 0x0094, 1);
- evo_data(push, 0x00000000);
- evo_mthd(push, 0x00c0, 1);
- evo_data(push, 0x00000000);
- evo_mthd(push, 0x0080, 1);
- evo_data(push, 0x00000000);
- evo_kick(push, sync);
+ struct nv50_display *disp = nv50_display(crtc->dev);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index];
+ struct nouveau_channel *evo = dispc->sync;
+ int ret;
+
+ ret = RING_SPACE(evo, 8);
+ if (ret) {
+ WARN_ON(1);
+ return;
}
+
+ BEGIN_NV04(evo, 0, 0x0084, 1);
+ OUT_RING (evo, 0x00000000);
+ BEGIN_NV04(evo, 0, 0x0094, 1);
+ OUT_RING (evo, 0x00000000);
+ BEGIN_NV04(evo, 0, 0x00c0, 1);
+ OUT_RING (evo, 0x00000000);
+ BEGIN_NV04(evo, 0, 0x0080, 1);
+ OUT_RING (evo, 0x00000000);
+ FIRE_RING (evo);
}
int
nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
- struct nouveau_channel *chan, u32 swap_interval)
+ struct nouveau_channel *chan)
{
+ struct nouveau_drm *drm = nouveau_drm(crtc->dev);
struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
- struct nv50_disp *disp = nv50_disp(crtc->dev);
+ struct nv50_display *disp = nv50_display(crtc->dev);
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- struct nv50_sync *sync = nv50_sync(crtc);
- u32 *push;
+ struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index];
+ struct nouveau_channel *evo = dispc->sync;
int ret;
- swap_interval <<= 4;
- if (swap_interval == 0)
- swap_interval |= 0x100;
-
- push = evo_wait(sync, 128);
- if (unlikely(push == NULL))
- return -EBUSY;
+ ret = RING_SPACE(evo, chan ? 25 : 27);
+ if (unlikely(ret))
+ return ret;
/* synchronise with the rendering channel, if necessary */
if (likely(chan)) {
ret = RING_SPACE(chan, 10);
- if (ret)
+ if (ret) {
+ WIND_RING(evo);
return ret;
+ }
- if (nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) {
- BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
+ if (nv_device(drm->device)->chipset < 0xc0) {
+ BEGIN_NV04(chan, 0, 0x0060, 2);
OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
- OUT_RING (chan, sync->sem.offset);
- BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
- OUT_RING (chan, 0xf00d0000 | sync->sem.value);
- BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2);
- OUT_RING (chan, sync->sem.offset ^ 0x10);
+ OUT_RING (chan, dispc->sem.offset);
+ BEGIN_NV04(chan, 0, 0x006c, 1);
+ OUT_RING (chan, 0xf00d0000 | dispc->sem.value);
+ BEGIN_NV04(chan, 0, 0x0064, 2);
+ OUT_RING (chan, dispc->sem.offset ^ 0x10);
OUT_RING (chan, 0x74b1e000);
- BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
- if (nv_mclass(chan->object) < NV84_CHANNEL_DMA_CLASS)
+ BEGIN_NV04(chan, 0, 0x0060, 1);
+ if (nv_device(drm->device)->chipset < 0x84)
OUT_RING (chan, NvSema);
else
OUT_RING (chan, chan->vram);
} else {
u64 offset = nvc0_fence_crtc(chan, nv_crtc->index);
- offset += sync->sem.offset;
-
- BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+ offset += dispc->sem.offset;
+ BEGIN_NVC0(chan, 0, 0x0010, 4);
OUT_RING (chan, upper_32_bits(offset));
OUT_RING (chan, lower_32_bits(offset));
- OUT_RING (chan, 0xf00d0000 | sync->sem.value);
+ OUT_RING (chan, 0xf00d0000 | dispc->sem.value);
OUT_RING (chan, 0x1002);
- BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+ BEGIN_NVC0(chan, 0, 0x0010, 4);
OUT_RING (chan, upper_32_bits(offset));
OUT_RING (chan, lower_32_bits(offset ^ 0x10));
OUT_RING (chan, 0x74b1e000);
OUT_RING (chan, 0x1001);
}
-
FIRE_RING (chan);
} else {
- nouveau_bo_wr32(disp->sync, sync->sem.offset / 4,
- 0xf00d0000 | sync->sem.value);
- evo_sync(crtc->dev);
+ nouveau_bo_wr32(dispc->sem.bo, dispc->sem.offset / 4,
+ 0xf00d0000 | dispc->sem.value);
}
- /* queue the flip */
- evo_mthd(push, 0x0100, 1);
- evo_data(push, 0xfffe0000);
- evo_mthd(push, 0x0084, 1);
- evo_data(push, swap_interval);
- if (!(swap_interval & 0x00000100)) {
- evo_mthd(push, 0x00e0, 1);
- evo_data(push, 0x40000000);
- }
- evo_mthd(push, 0x0088, 4);
- evo_data(push, sync->sem.offset);
- evo_data(push, 0xf00d0000 | sync->sem.value);
- evo_data(push, 0x74b1e000);
- evo_data(push, NvEvoSync);
- evo_mthd(push, 0x00a0, 2);
- evo_data(push, 0x00000000);
- evo_data(push, 0x00000000);
- evo_mthd(push, 0x00c0, 1);
- evo_data(push, nv_fb->r_dma);
- evo_mthd(push, 0x0110, 2);
- evo_data(push, 0x00000000);
- evo_data(push, 0x00000000);
- if (nv50_vers(sync) < NVD0_DISP_SYNC_CLASS) {
- evo_mthd(push, 0x0800, 5);
- evo_data(push, nv_fb->nvbo->bo.offset >> 8);
- evo_data(push, 0);
- evo_data(push, (fb->height << 16) | fb->width);
- evo_data(push, nv_fb->r_pitch);
- evo_data(push, nv_fb->r_format);
+ /* queue the flip on the crtc's "display sync" channel */
+ BEGIN_NV04(evo, 0, 0x0100, 1);
+ OUT_RING (evo, 0xfffe0000);
+ if (chan) {
+ BEGIN_NV04(evo, 0, 0x0084, 1);
+ OUT_RING (evo, 0x00000100);
} else {
- evo_mthd(push, 0x0400, 5);
- evo_data(push, nv_fb->nvbo->bo.offset >> 8);
- evo_data(push, 0);
- evo_data(push, (fb->height << 16) | fb->width);
- evo_data(push, nv_fb->r_pitch);
- evo_data(push, nv_fb->r_format);
- }
- evo_mthd(push, 0x0080, 1);
- evo_data(push, 0x00000000);
- evo_kick(push, sync);
-
- sync->sem.offset ^= 0x10;
- sync->sem.value++;
+ BEGIN_NV04(evo, 0, 0x0084, 1);
+ OUT_RING (evo, 0x00000010);
+ /* allows gamma somehow, PDISP will bitch at you if
+ * you don't wait for vblank before changing this..
+ */
+ BEGIN_NV04(evo, 0, 0x00e0, 1);
+ OUT_RING (evo, 0x40000000);
+ }
+ BEGIN_NV04(evo, 0, 0x0088, 4);
+ OUT_RING (evo, dispc->sem.offset);
+ OUT_RING (evo, 0xf00d0000 | dispc->sem.value);
+ OUT_RING (evo, 0x74b1e000);
+ OUT_RING (evo, NvEvoSync);
+ BEGIN_NV04(evo, 0, 0x00a0, 2);
+ OUT_RING (evo, 0x00000000);
+ OUT_RING (evo, 0x00000000);
+ BEGIN_NV04(evo, 0, 0x00c0, 1);
+ OUT_RING (evo, nv_fb->r_dma);
+ BEGIN_NV04(evo, 0, 0x0110, 2);
+ OUT_RING (evo, 0x00000000);
+ OUT_RING (evo, 0x00000000);
+ BEGIN_NV04(evo, 0, 0x0800, 5);
+ 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);
+ OUT_RING (evo, nv_fb->r_format);
+ BEGIN_NV04(evo, 0, 0x0080, 1);
+ OUT_RING (evo, 0x00000000);
+ FIRE_RING (evo);
+
+ dispc->sem.offset ^= 0x10;
+ dispc->sem.value++;
return 0;
}
-/******************************************************************************
- * CRTC
- *****************************************************************************/
-static int
-nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
+static u16
+nv50_display_script_select(struct drm_device *dev, struct dcb_output *dcb,
+ u32 mc, int pxclk)
{
- struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
- struct nouveau_connector *nv_connector;
- struct drm_connector *connector;
- u32 *push, mode = 0x00;
-
- nv_connector = nouveau_crtc_connector_get(nv_crtc);
- connector = &nv_connector->base;
- if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
- if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
- mode = DITHERING_MODE_DYNAMIC2X2;
- } else {
- mode = nv_connector->dithering_mode;
- }
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_connector *nv_connector = NULL;
+ struct drm_encoder *encoder;
+ struct nvbios *bios = &drm->vbios;
+ u32 script = 0, or;
- if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) {
- if (connector->display_info.bpc >= 8)
- mode |= DITHERING_DEPTH_8BPC;
- } else {
- mode |= nv_connector->dithering_depth;
- }
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- push = evo_wait(mast, 4);
- if (push) {
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x08a0 + (nv_crtc->index * 0x0400), 1);
- evo_data(push, mode);
- } else
- if (nv50_vers(mast) < NVE0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0490 + (nv_crtc->index * 0x0300), 1);
- evo_data(push, mode);
- } else {
- evo_mthd(push, 0x04a0 + (nv_crtc->index * 0x0300), 1);
- evo_data(push, mode);
- }
+ if (nv_encoder->dcb != dcb)
+ continue;
- if (update) {
- evo_mthd(push, 0x0080, 1);
- evo_data(push, 0x00000000);
- }
- evo_kick(push, mast);
+ nv_connector = nouveau_encoder_connector_get(nv_encoder);
+ break;
}
- return 0;
-}
-
-static int
-nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
-{
- struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
- struct drm_display_mode *omode, *umode = &nv_crtc->base.mode;
- struct drm_crtc *crtc = &nv_crtc->base;
- struct nouveau_connector *nv_connector;
- int mode = DRM_MODE_SCALE_NONE;
- u32 oX, oY, *push;
-
- /* start off at the resolution we programmed the crtc for, this
- * effectively handles NONE/FULL scaling
- */
- nv_connector = nouveau_crtc_connector_get(nv_crtc);
- if (nv_connector && nv_connector->native_mode)
- mode = nv_connector->scaling_mode;
-
- if (mode != DRM_MODE_SCALE_NONE)
- omode = nv_connector->native_mode;
- else
- omode = umode;
-
- oX = omode->hdisplay;
- oY = omode->vdisplay;
- if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
- oY *= 2;
-
- /* add overscan compensation if necessary, will keep the aspect
- * ratio the same as the backend mode unless overridden by the
- * user setting both hborder and vborder properties.
- */
- if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
- (nv_connector->underscan == UNDERSCAN_AUTO &&
- nv_connector->edid &&
- drm_detect_hdmi_monitor(nv_connector->edid)))) {
- u32 bX = nv_connector->underscan_hborder;
- u32 bY = nv_connector->underscan_vborder;
- u32 aspect = (oY << 19) / oX;
-
- if (bX) {
- oX -= (bX * 2);
- if (bY) oY -= (bY * 2);
- else oY = ((oX * aspect) + (aspect / 2)) >> 19;
+ or = ffs(dcb->or) - 1;
+ switch (dcb->type) {
+ case DCB_OUTPUT_LVDS:
+ script = (mc >> 8) & 0xf;
+ if (bios->fp_no_ddc) {
+ if (bios->fp.dual_link)
+ script |= 0x0100;
+ if (bios->fp.if_is_24bit)
+ script |= 0x0200;
} else {
- oX -= (oX >> 4) + 32;
- if (bY) oY -= (bY * 2);
- else oY = ((oX * aspect) + (aspect / 2)) >> 19;
- }
- }
+ /* determine number of lvds links */
+ if (nv_connector && nv_connector->edid &&
+ nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
+ /* http://www.spwg.org */
+ if (((u8 *)nv_connector->edid)[121] == 2)
+ script |= 0x0100;
+ } else
+ if (pxclk >= bios->fp.duallink_transition_clk) {
+ script |= 0x0100;
+ }
- /* handle CENTER/ASPECT scaling, taking into account the areas
- * removed already for overscan compensation
- */
- switch (mode) {
- case DRM_MODE_SCALE_CENTER:
- oX = min((u32)umode->hdisplay, oX);
- oY = min((u32)umode->vdisplay, oY);
- /* fall-through */
- case DRM_MODE_SCALE_ASPECT:
- if (oY < oX) {
- u32 aspect = (umode->hdisplay << 19) / umode->vdisplay;
- oX = ((oY * aspect) + (aspect / 2)) >> 19;
- } else {
- u32 aspect = (umode->vdisplay << 19) / umode->hdisplay;
- oY = ((oX * aspect) + (aspect / 2)) >> 19;
+ /* determine panel depth */
+ if (script & 0x0100) {
+ if (bios->fp.strapless_is_24bit & 2)
+ script |= 0x0200;
+ } else {
+ if (bios->fp.strapless_is_24bit & 1)
+ script |= 0x0200;
+ }
+
+ if (nv_connector && nv_connector->edid &&
+ (nv_connector->edid->revision >= 4) &&
+ (nv_connector->edid->input & 0x70) >= 0x20)
+ script |= 0x0200;
}
break;
+ case DCB_OUTPUT_TMDS:
+ script = (mc >> 8) & 0xf;
+ if (pxclk >= 165000)
+ script |= 0x0100;
+ break;
+ case DCB_OUTPUT_DP:
+ script = (mc >> 8) & 0xf;
+ break;
+ case DCB_OUTPUT_ANALOG:
+ script = 0xff;
+ break;
default:
+ NV_ERROR(drm, "modeset on unsupported output type!\n");
break;
}
- push = evo_wait(mast, 8);
- if (push) {
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- /*XXX: SCALE_CTRL_ACTIVE??? */
- evo_mthd(push, 0x08d8 + (nv_crtc->index * 0x400), 2);
- evo_data(push, (oY << 16) | oX);
- evo_data(push, (oY << 16) | oX);
- evo_mthd(push, 0x08a4 + (nv_crtc->index * 0x400), 1);
- evo_data(push, 0x00000000);
- evo_mthd(push, 0x08c8 + (nv_crtc->index * 0x400), 1);
- evo_data(push, umode->vdisplay << 16 | umode->hdisplay);
- } else {
- evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
- evo_data(push, (oY << 16) | oX);
- evo_data(push, (oY << 16) | oX);
- evo_data(push, (oY << 16) | oX);
- 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, umode->vdisplay << 16 | umode->hdisplay);
- }
+ return script;
+}
- evo_kick(push, mast);
+static void
+nv50_display_unk10_handler(struct drm_device *dev)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nv50_display *disp = nv50_display(dev);
+ u32 unk30 = nv_rd32(device, 0x610030), mc;
+ int i, crtc, or = 0, type = DCB_OUTPUT_ANY;
- if (update) {
- nv50_display_flip_stop(crtc);
- nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
- }
- }
+ NV_DEBUG(drm, "0x610030: 0x%08x\n", unk30);
+ disp->irq.dcb = NULL;
- return 0;
-}
+ nv_wr32(device, 0x619494, nv_rd32(device, 0x619494) & ~8);
-static int
-nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
-{
- struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
- u32 *push, hue, vib;
- int adj;
-
- adj = (nv_crtc->color_vibrance > 0) ? 50 : 0;
- vib = ((nv_crtc->color_vibrance * 2047 + adj) / 100) & 0xfff;
- hue = ((nv_crtc->vibrant_hue * 2047) / 100) & 0xfff;
-
- push = evo_wait(mast, 16);
- if (push) {
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x08a8 + (nv_crtc->index * 0x400), 1);
- evo_data(push, (hue << 20) | (vib << 8));
- } else {
- evo_mthd(push, 0x0498 + (nv_crtc->index * 0x300), 1);
- evo_data(push, (hue << 20) | (vib << 8));
- }
+ /* Determine which CRTC we're dealing with, only 1 ever will be
+ * signalled at the same time with the current nouveau code.
+ */
+ crtc = ffs((unk30 & 0x00000060) >> 5) - 1;
+ if (crtc < 0)
+ goto ack;
+
+ /* Nothing needs to be done for the encoder */
+ crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
+ if (crtc < 0)
+ goto ack;
+
+ /* Find which encoder was connected to the CRTC */
+ for (i = 0; type == DCB_OUTPUT_ANY && i < 3; i++) {
+ mc = nv_rd32(device, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
+ NV_DEBUG(drm, "DAC-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
- if (update) {
- evo_mthd(push, 0x0080, 1);
- evo_data(push, 0x00000000);
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = DCB_OUTPUT_ANALOG; break;
+ case 1: type = DCB_OUTPUT_TV; break;
+ default:
+ NV_ERROR(drm, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
+ goto ack;
}
- evo_kick(push, mast);
+
+ or = i;
}
- return 0;
-}
+ for (i = 0; type == DCB_OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
+ if (nv_device(drm->device)->chipset < 0x90 ||
+ nv_device(drm->device)->chipset == 0x92 ||
+ nv_device(drm->device)->chipset == 0xa0)
+ mc = nv_rd32(device, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
+ else
+ mc = nv_rd32(device, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
-static int
-nv50_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);
- struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
- u32 *push;
-
- push = evo_wait(mast, 16);
- if (push) {
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0860 + (nv_crtc->index * 0x400), 1);
- evo_data(push, nvfb->nvbo->bo.offset >> 8);
- evo_mthd(push, 0x0868 + (nv_crtc->index * 0x400), 3);
- evo_data(push, (fb->height << 16) | fb->width);
- evo_data(push, nvfb->r_pitch);
- evo_data(push, nvfb->r_format);
- evo_mthd(push, 0x08c0 + (nv_crtc->index * 0x400), 1);
- evo_data(push, (y << 16) | x);
- if (nv50_vers(mast) > NV50_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
- evo_data(push, nvfb->r_dma);
- }
- } else {
- 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);
- }
+ NV_DEBUG(drm, "SOR-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
- if (update) {
- evo_mthd(push, 0x0080, 1);
- evo_data(push, 0x00000000);
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = DCB_OUTPUT_LVDS; break;
+ case 1: type = DCB_OUTPUT_TMDS; break;
+ case 2: type = DCB_OUTPUT_TMDS; break;
+ case 5: type = DCB_OUTPUT_TMDS; break;
+ case 8: type = DCB_OUTPUT_DP; break;
+ case 9: type = DCB_OUTPUT_DP; break;
+ default:
+ NV_ERROR(drm, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
+ goto ack;
}
- evo_kick(push, mast);
+
+ or = i;
}
- nv_crtc->fb.tile_flags = nvfb->r_dma;
- return 0;
-}
+ /* There was no encoder to disable */
+ if (type == DCB_OUTPUT_ANY)
+ goto ack;
-static void
-nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc)
-{
- struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
- u32 *push = evo_wait(mast, 16);
- if (push) {
- if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
- evo_data(push, 0x85000000);
- evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
- } else
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
- evo_data(push, 0x85000000);
- evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
- evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
- evo_data(push, NvEvoVRAM);
- } else {
- 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);
- }
- evo_kick(push, mast);
- }
-}
+ /* Disable the encoder */
+ for (i = 0; i < drm->vbios.dcb.entries; i++) {
+ struct dcb_output *dcb = &drm->vbios.dcb.entry[i];
-static void
-nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc)
-{
- struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
- u32 *push = evo_wait(mast, 16);
- if (push) {
- if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1);
- evo_data(push, 0x05000000);
- } else
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1);
- evo_data(push, 0x05000000);
- evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
- evo_data(push, 0x00000000);
- } 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 (dcb->type == type && (dcb->or & (1 << or))) {
+ nouveau_bios_run_display_table(dev, 0, -1, dcb, -1);
+ disp->irq.dcb = dcb;
+ goto ack;
}
- evo_kick(push, mast);
}
+
+ NV_ERROR(drm, "no dcb for %d %d 0x%08x\n", or, type, mc);
+ack:
+ nv_wr32(device, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10);
+ nv_wr32(device, 0x610030, 0x80000000);
}
static void
-nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
+nv50_display_unk20_handler(struct drm_device *dev)
{
- struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
-
- if (show)
- nv50_crtc_cursor_show(nv_crtc);
- else
- nv50_crtc_cursor_hide(nv_crtc);
-
- if (update) {
- u32 *push = evo_wait(mast, 2);
- if (push) {
- evo_mthd(push, 0x0080, 1);
- evo_data(push, 0x00000000);
- evo_kick(push, mast);
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nv50_display *disp = nv50_display(dev);
+ u32 unk30 = nv_rd32(device, 0x610030), tmp, pclk, script, mc = 0;
+ struct dcb_output *dcb;
+ int i, crtc, or = 0, type = DCB_OUTPUT_ANY;
+
+ NV_DEBUG(drm, "0x610030: 0x%08x\n", unk30);
+ dcb = disp->irq.dcb;
+ if (dcb) {
+ nouveau_bios_run_display_table(dev, 0, -2, dcb, -1);
+ disp->irq.dcb = NULL;
+ }
+
+ /* CRTC clock change requested? */
+ crtc = ffs((unk30 & 0x00000600) >> 9) - 1;
+ if (crtc >= 0) {
+ pclk = nv_rd32(device, NV50_PDISPLAY_CRTC_P(crtc, CLOCK));
+ pclk &= 0x003fffff;
+ if (pclk)
+ nv50_crtc_set_clock(dev, crtc, pclk);
+
+ tmp = nv_rd32(device, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc));
+ tmp &= ~0x000000f;
+ nv_wr32(device, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp);
+ }
+
+ /* Nothing needs to be done for the encoder */
+ crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
+ if (crtc < 0)
+ goto ack;
+ pclk = nv_rd32(device, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff;
+
+ /* Find which encoder is connected to the CRTC */
+ for (i = 0; type == DCB_OUTPUT_ANY && i < 3; i++) {
+ mc = nv_rd32(device, NV50_PDISPLAY_DAC_MODE_CTRL_P(i));
+ NV_DEBUG(drm, "DAC-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
+
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = DCB_OUTPUT_ANALOG; break;
+ case 1: type = DCB_OUTPUT_TV; break;
+ default:
+ NV_ERROR(drm, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
+ goto ack;
}
+
+ or = i;
}
-}
-static void
-nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
-}
+ for (i = 0; type == DCB_OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
+ if (nv_device(drm->device)->chipset < 0x90 ||
+ nv_device(drm->device)->chipset == 0x92 ||
+ nv_device(drm->device)->chipset == 0xa0)
+ mc = nv_rd32(device, NV50_PDISPLAY_SOR_MODE_CTRL_P(i));
+ else
+ mc = nv_rd32(device, NV90_PDISPLAY_SOR_MODE_CTRL_P(i));
-static void
-nv50_crtc_prepare(struct drm_crtc *crtc)
-{
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- struct nv50_mast *mast = nv50_mast(crtc->dev);
- u32 *push;
-
- nv50_display_flip_stop(crtc);
-
- push = evo_wait(mast, 2);
- if (push) {
- if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
- evo_data(push, 0x00000000);
- evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1);
- evo_data(push, 0x40000000);
- } else
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
- evo_data(push, 0x00000000);
- evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1);
- evo_data(push, 0x40000000);
- evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1);
- evo_data(push, 0x00000000);
- } else {
- 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);
+ NV_DEBUG(drm, "SOR-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
+
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = DCB_OUTPUT_LVDS; break;
+ case 1: type = DCB_OUTPUT_TMDS; break;
+ case 2: type = DCB_OUTPUT_TMDS; break;
+ case 5: type = DCB_OUTPUT_TMDS; break;
+ case 8: type = DCB_OUTPUT_DP; break;
+ case 9: type = DCB_OUTPUT_DP; break;
+ default:
+ NV_ERROR(drm, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
+ goto ack;
}
- evo_kick(push, mast);
+ or = i;
}
- nv50_crtc_cursor_show_hide(nv_crtc, false, false);
-}
-
-static void
-nv50_crtc_commit(struct drm_crtc *crtc)
-{
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- struct nv50_mast *mast = nv50_mast(crtc->dev);
- u32 *push;
-
- push = evo_wait(mast, 32);
- if (push) {
- if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
- evo_data(push, NvEvoVRAM_LP);
- evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2);
- evo_data(push, 0xc0000000);
- evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
- } else
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
- evo_data(push, nv_crtc->fb.tile_flags);
- evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2);
- evo_data(push, 0xc0000000);
- evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
- evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1);
- evo_data(push, NvEvoVRAM);
- } else {
- 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, mast);
- }
-
- nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true);
- nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
-}
-
-static bool
-nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
-static int
-nv50_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
-nv50_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 nv50_mast *mast = nv50_mast(crtc->dev);
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- struct nouveau_connector *nv_connector;
- u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
- u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
- u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
- u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
- u32 vblan2e = 0, vblan2s = 1;
- u32 *push;
- int ret;
-
- hactive = mode->htotal;
- hsynce = mode->hsync_end - mode->hsync_start - 1;
- hbackp = mode->htotal - mode->hsync_end;
- hblanke = hsynce + hbackp;
- hfrontp = mode->hsync_start - mode->hdisplay;
- hblanks = mode->htotal - hfrontp - 1;
-
- vactive = mode->vtotal * vscan / ilace;
- vsynce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
- vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
- vblanke = vsynce + vbackp;
- vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
- vblanks = vactive - vfrontp - 1;
- if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
- vblan2e = vactive + vsynce + vbackp;
- vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
- vactive = (vactive * 2) + 1;
- }
-
- ret = nv50_crtc_swap_fbs(crtc, old_fb);
- if (ret)
- return ret;
-
- push = evo_wait(mast, 64);
- if (push) {
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0804 + (nv_crtc->index * 0x400), 2);
- evo_data(push, 0x00800000 | mode->clock);
- evo_data(push, (ilace == 2) ? 2 : 0);
- evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 6);
- evo_data(push, 0x00000000);
- evo_data(push, (vactive << 16) | hactive);
- evo_data(push, ( vsynce << 16) | hsynce);
- evo_data(push, (vblanke << 16) | hblanke);
- evo_data(push, (vblanks << 16) | hblanks);
- evo_data(push, (vblan2e << 16) | vblan2s);
- evo_mthd(push, 0x082c + (nv_crtc->index * 0x400), 1);
- evo_data(push, 0x00000000);
- evo_mthd(push, 0x0900 + (nv_crtc->index * 0x400), 2);
- evo_data(push, 0x00000311);
- evo_data(push, 0x00000100);
- } else {
- evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 6);
- evo_data(push, 0x00000000);
- evo_data(push, (vactive << 16) | hactive);
- evo_data(push, ( vsynce << 16) | hsynce);
- evo_data(push, (vblanke << 16) | hblanke);
- evo_data(push, (vblanks << 16) | hblanks);
- evo_data(push, (vblan2e << 16) | vblan2s);
- 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, 0x04d0 + (nv_crtc->index * 0x300), 2);
- evo_data(push, 0x00000311);
- evo_data(push, 0x00000100);
- }
-
- evo_kick(push, mast);
- }
-
- nv_connector = nouveau_crtc_connector_get(nv_crtc);
- nv50_crtc_set_dither(nv_crtc, false);
- nv50_crtc_set_scale(nv_crtc, false);
- nv50_crtc_set_color_vibrance(nv_crtc, false);
- nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
- return 0;
-}
-
-static int
-nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
-{
- struct nouveau_drm *drm = nouveau_drm(crtc->dev);
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- int ret;
-
- if (!crtc->fb) {
- NV_DEBUG(drm, "No FB bound\n");
- return 0;
- }
-
- ret = nv50_crtc_swap_fbs(crtc, old_fb);
- if (ret)
- return ret;
-
- nv50_display_flip_stop(crtc);
- nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
- nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
- return 0;
-}
-
-static int
-nv50_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);
- nv50_display_flip_stop(crtc);
- nv50_crtc_set_image(nv_crtc, fb, x, y, true);
- return 0;
-}
-
-static void
-nv50_crtc_lut_load(struct drm_crtc *crtc)
-{
- struct nv50_disp *disp = nv50_disp(crtc->dev);
- 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++) {
- u16 r = nv_crtc->lut.r[i] >> 2;
- u16 g = nv_crtc->lut.g[i] >> 2;
- u16 b = nv_crtc->lut.b[i] >> 2;
-
- if (nv_mclass(disp->core) < NVD0_DISP_CLASS) {
- writew(r + 0x0000, lut + (i * 0x08) + 0);
- writew(g + 0x0000, lut + (i * 0x08) + 2);
- writew(b + 0x0000, lut + (i * 0x08) + 4);
- } else {
- writew(r + 0x6000, lut + (i * 0x20) + 0);
- writew(g + 0x6000, lut + (i * 0x20) + 2);
- writew(b + 0x6000, lut + (i * 0x20) + 4);
- }
- }
-}
-
-static int
-nv50_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) {
- nv50_crtc_cursor_show_hide(nv_crtc, visible, true);
- nv_crtc->cursor.visible = visible;
- }
-
- return ret;
-}
-
-static int
-nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
-{
- struct nv50_curs *curs = nv50_curs(crtc);
- struct nv50_chan *chan = nv50_chan(curs);
- nv_wo32(chan->user, 0x0084, (y << 16) | (x & 0xffff));
- nv_wo32(chan->user, 0x0080, 0x00000000);
- return 0;
-}
-
-static void
-nv50_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];
- }
-
- nv50_crtc_lut_load(crtc);
-}
-
-static void
-nv50_crtc_destroy(struct drm_crtc *crtc)
-{
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- struct nv50_disp *disp = nv50_disp(crtc->dev);
- struct nv50_head *head = nv50_head(crtc);
- nv50_dmac_destroy(disp->core, &head->ovly.base);
- nv50_pioc_destroy(disp->core, &head->oimm.base);
- nv50_dmac_destroy(disp->core, &head->sync.base);
- nv50_pioc_destroy(disp->core, &head->curs.base);
- nouveau_bo_unmap(nv_crtc->cursor.nvbo);
- if (nv_crtc->cursor.nvbo)
- nouveau_bo_unpin(nv_crtc->cursor.nvbo);
- nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
- nouveau_bo_unmap(nv_crtc->lut.nvbo);
- if (nv_crtc->lut.nvbo)
- nouveau_bo_unpin(nv_crtc->lut.nvbo);
- nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
- drm_crtc_cleanup(crtc);
- kfree(crtc);
-}
+ if (type == DCB_OUTPUT_ANY)
+ goto ack;
-static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
- .dpms = nv50_crtc_dpms,
- .prepare = nv50_crtc_prepare,
- .commit = nv50_crtc_commit,
- .mode_fixup = nv50_crtc_mode_fixup,
- .mode_set = nv50_crtc_mode_set,
- .mode_set_base = nv50_crtc_mode_set_base,
- .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
- .load_lut = nv50_crtc_lut_load,
-};
-
-static const struct drm_crtc_funcs nv50_crtc_func = {
- .cursor_set = nv50_crtc_cursor_set,
- .cursor_move = nv50_crtc_cursor_move,
- .gamma_set = nv50_crtc_gamma_set,
- .set_config = drm_crtc_helper_set_config,
- .destroy = nv50_crtc_destroy,
- .page_flip = nouveau_crtc_page_flip,
-};
-
-static void
-nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
-{
-}
-
-static void
-nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
-{
-}
-
-static int
-nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index)
-{
- struct nv50_disp *disp = nv50_disp(dev);
- struct nv50_head *head;
- struct drm_crtc *crtc;
- int ret, i;
-
- head = kzalloc(sizeof(*head), GFP_KERNEL);
- if (!head)
- return -ENOMEM;
-
- head->base.index = index;
- head->base.set_dither = nv50_crtc_set_dither;
- head->base.set_scale = nv50_crtc_set_scale;
- head->base.set_color_vibrance = nv50_crtc_set_color_vibrance;
- head->base.color_vibrance = 50;
- head->base.vibrant_hue = 0;
- head->base.cursor.set_offset = nv50_cursor_set_offset;
- head->base.cursor.set_pos = nv50_cursor_set_pos;
- for (i = 0; i < 256; i++) {
- head->base.lut.r[i] = i << 8;
- head->base.lut.g[i] = i << 8;
- head->base.lut.b[i] = i << 8;
+ /* Enable the encoder */
+ for (i = 0; i < drm->vbios.dcb.entries; i++) {
+ dcb = &drm->vbios.dcb.entry[i];
+ if (dcb->type == type && (dcb->or & (1 << or)))
+ break;
}
- crtc = &head->base.base;
- drm_crtc_init(dev, crtc, &nv50_crtc_func);
- drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
- drm_mode_crtc_set_gamma_size(crtc, 256);
-
- ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, NULL, &head->base.lut.nvbo);
- if (!ret) {
- ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM);
- if (!ret) {
- ret = nouveau_bo_map(head->base.lut.nvbo);
- if (ret)
- nouveau_bo_unpin(head->base.lut.nvbo);
- }
- if (ret)
- nouveau_bo_ref(NULL, &head->base.lut.nvbo);
+ if (i == drm->vbios.dcb.entries) {
+ NV_ERROR(drm, "no dcb for %d %d 0x%08x\n", or, type, mc);
+ goto ack;
}
- if (ret)
- goto out;
-
- nv50_crtc_lut_load(crtc);
+ script = nv50_display_script_select(dev, dcb, mc, pclk);
+ nouveau_bios_run_display_table(dev, script, pclk, dcb, -1);
- /* allocate cursor resources */
- ret = nv50_pioc_create(disp->core, NV50_DISP_CURS_CLASS, index,
- &(struct nv50_display_curs_class) {
- .head = index,
- }, sizeof(struct nv50_display_curs_class),
- &head->curs.base);
- if (ret)
- goto out;
-
- ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, NULL, &head->base.cursor.nvbo);
- if (!ret) {
- ret = nouveau_bo_pin(head->base.cursor.nvbo, TTM_PL_FLAG_VRAM);
- if (!ret) {
- ret = nouveau_bo_map(head->base.cursor.nvbo);
- if (ret)
- nouveau_bo_unpin(head->base.lut.nvbo);
- }
- if (ret)
- nouveau_bo_ref(NULL, &head->base.cursor.nvbo);
- }
-
- if (ret)
- goto out;
-
- /* allocate page flip / sync resources */
- ret = nv50_dmac_create(disp->core, NV50_DISP_SYNC_CLASS, index,
- &(struct nv50_display_sync_class) {
- .pushbuf = EVO_PUSH_HANDLE(SYNC, index),
- .head = index,
- }, sizeof(struct nv50_display_sync_class),
- disp->sync->bo.offset, &head->sync.base);
- if (ret)
- goto out;
-
- head->sync.sem.offset = EVO_SYNC(1 + index, 0x00);
-
- /* allocate overlay resources */
- ret = nv50_pioc_create(disp->core, NV50_DISP_OIMM_CLASS, index,
- &(struct nv50_display_oimm_class) {
- .head = index,
- }, sizeof(struct nv50_display_oimm_class),
- &head->oimm.base);
- if (ret)
- goto out;
-
- ret = nv50_dmac_create(disp->core, NV50_DISP_OVLY_CLASS, index,
- &(struct nv50_display_ovly_class) {
- .pushbuf = EVO_PUSH_HANDLE(OVLY, index),
- .head = index,
- }, sizeof(struct nv50_display_ovly_class),
- disp->sync->bo.offset, &head->ovly.base);
- if (ret)
- goto out;
-
-out:
- if (ret)
- nv50_crtc_destroy(crtc);
- return ret;
-}
-
-/******************************************************************************
- * DAC
- *****************************************************************************/
-static void
-nv50_dac_dpms(struct drm_encoder *encoder, int mode)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nv50_disp *disp = nv50_disp(encoder->dev);
- int or = nv_encoder->or;
- u32 dpms_ctrl;
-
- dpms_ctrl = 0x00000000;
- 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_call(disp->core, NV50_DISP_DAC_PWR + or, dpms_ctrl);
-}
-
-static bool
-nv50_dac_mode_fixup(struct drm_encoder *encoder,
- const 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
-nv50_dac_commit(struct drm_encoder *encoder)
-{
-}
-
-static void
-nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct nv50_mast *mast = nv50_mast(encoder->dev);
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
- u32 *push;
-
- nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
-
- push = evo_wait(mast, 8);
- if (push) {
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- u32 syncs = 0x00000000;
-
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- syncs |= 0x00000001;
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- syncs |= 0x00000002;
-
- evo_mthd(push, 0x0400 + (nv_encoder->or * 0x080), 2);
- evo_data(push, 1 << nv_crtc->index);
- evo_data(push, syncs);
- } else {
- u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
- u32 syncs = 0x00000001;
-
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- syncs |= 0x00000008;
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- syncs |= 0x00000010;
-
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- magic |= 0x00000001;
-
- evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
- evo_data(push, syncs);
- evo_data(push, magic);
- evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 1);
- evo_data(push, 1 << nv_crtc->index);
- }
-
- evo_kick(push, mast);
+ if (type == DCB_OUTPUT_DP) {
+ int link = !(dcb->dpconf.sor.link & 1);
+ if ((mc & 0x000f0000) == 0x00020000)
+ nv50_sor_dp_calc_tu(dev, or, link, pclk, 18);
+ else
+ nv50_sor_dp_calc_tu(dev, or, link, pclk, 24);
}
- nv_encoder->crtc = encoder->crtc;
-}
-
-static void
-nv50_dac_disconnect(struct drm_encoder *encoder)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nv50_mast *mast = nv50_mast(encoder->dev);
- const int or = nv_encoder->or;
- u32 *push;
-
- if (nv_encoder->crtc) {
- nv50_crtc_prepare(nv_encoder->crtc);
-
- push = evo_wait(mast, 4);
- if (push) {
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0400 + (or * 0x080), 1);
- evo_data(push, 0x00000000);
- } else {
- evo_mthd(push, 0x0180 + (or * 0x020), 1);
- evo_data(push, 0x00000000);
- }
-
- evo_mthd(push, 0x0080, 1);
- evo_data(push, 0x00000000);
- evo_kick(push, mast);
- }
+ if (dcb->type != DCB_OUTPUT_ANALOG) {
+ tmp = nv_rd32(device, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
+ tmp &= ~0x00000f0f;
+ if (script & 0x0100)
+ tmp |= 0x00000101;
+ nv_wr32(device, NV50_PDISPLAY_SOR_CLK_CTRL2(or), tmp);
+ } else {
+ nv_wr32(device, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
}
- nv_encoder->crtc = NULL;
-}
-
-static enum drm_connector_status
-nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
-{
- struct nv50_disp *disp = nv50_disp(encoder->dev);
- int ret, or = nouveau_encoder(encoder)->or;
- u32 load = 0;
-
- ret = nv_exec(disp->core, NV50_DISP_DAC_LOAD + or, &load, sizeof(load));
- if (ret || load != 7)
- return connector_status_disconnected;
+ disp->irq.dcb = dcb;
+ disp->irq.pclk = pclk;
+ disp->irq.script = script;
- return connector_status_connected;
+ack:
+ nv_wr32(device, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20);
+ nv_wr32(device, 0x610030, 0x80000000);
}
+/* If programming a TMDS output on a SOR that can also be configured for
+ * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
+ *
+ * It looks like the VBIOS TMDS scripts make an attempt at this, however,
+ * the VBIOS scripts on at least one board I have only switch it off on
+ * link 0, causing a blank display if the output has previously been
+ * programmed for DisplayPort.
+ */
static void
-nv50_dac_destroy(struct drm_encoder *encoder)
+nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_output *dcb)
{
- drm_encoder_cleanup(encoder);
- kfree(encoder);
-}
-
-static const struct drm_encoder_helper_funcs nv50_dac_hfunc = {
- .dpms = nv50_dac_dpms,
- .mode_fixup = nv50_dac_mode_fixup,
- .prepare = nv50_dac_disconnect,
- .commit = nv50_dac_commit,
- .mode_set = nv50_dac_mode_set,
- .disable = nv50_dac_disconnect,
- .get_crtc = nv50_display_crtc_get,
- .detect = nv50_dac_detect
-};
-
-static const struct drm_encoder_funcs nv50_dac_func = {
- .destroy = nv50_dac_destroy,
-};
-
-static int
-nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
-{
- struct drm_device *dev = connector->dev;
- struct nouveau_encoder *nv_encoder;
+ struct nouveau_device *device = nouveau_dev(dev);
+ int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
struct drm_encoder *encoder;
+ u32 tmp;
- 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, &nv50_dac_func, DRM_MODE_ENCODER_DAC);
- drm_encoder_helper_add(encoder, &nv50_dac_hfunc);
-
- drm_mode_connector_attach_encoder(connector, encoder);
- return 0;
-}
-
-/******************************************************************************
- * Audio
- *****************************************************************************/
-static void
-nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nouveau_connector *nv_connector;
- struct nv50_disp *disp = nv50_disp(encoder->dev);
-
- nv_connector = nouveau_encoder_connector_get(nv_encoder);
- if (!drm_detect_monitor_audio(nv_connector->edid))
+ if (dcb->type != DCB_OUTPUT_TMDS)
return;
- drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
-
- nv_exec(disp->core, NVA3_DISP_SOR_HDA_ELD + nv_encoder->or,
- nv_connector->base.eld,
- nv_connector->base.eld[2] * 4);
-}
-
-static void
-nv50_audio_disconnect(struct drm_encoder *encoder)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nv50_disp *disp = nv50_disp(encoder->dev);
-
- nv_exec(disp->core, NVA3_DISP_SOR_HDA_ELD + nv_encoder->or, NULL, 0);
-}
-
-/******************************************************************************
- * HDMI
- *****************************************************************************/
-static void
-nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
- struct nouveau_connector *nv_connector;
- struct nv50_disp *disp = nv50_disp(encoder->dev);
- const u32 moff = (nv_crtc->index << 3) | nv_encoder->or;
- u32 rekey = 56; /* binary driver, and tegra constant */
- u32 max_ac_packet;
-
- nv_connector = nouveau_encoder_connector_get(nv_encoder);
- if (!drm_detect_hdmi_monitor(nv_connector->edid))
- return;
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- max_ac_packet = mode->htotal - mode->hdisplay;
- max_ac_packet -= rekey;
- max_ac_packet -= 18; /* constant from tegra */
- max_ac_packet /= 32;
-
- nv_call(disp->core, NV84_DISP_SOR_HDMI_PWR + moff,
- NV84_DISP_SOR_HDMI_PWR_STATE_ON |
- (max_ac_packet << 16) | rekey);
-
- nv50_audio_mode_set(encoder, mode);
-}
-
-static void
-nv50_hdmi_disconnect(struct drm_encoder *encoder)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
- struct nv50_disp *disp = nv50_disp(encoder->dev);
- const u32 moff = (nv_crtc->index << 3) | nv_encoder->or;
-
- nv50_audio_disconnect(encoder);
-
- nv_call(disp->core, NV84_DISP_SOR_HDMI_PWR + moff, 0x00000000);
-}
-
-/******************************************************************************
- * SOR
- *****************************************************************************/
-static void
-nv50_sor_dpms(struct drm_encoder *encoder, int mode)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct drm_device *dev = encoder->dev;
- struct nv50_disp *disp = nv50_disp(dev);
- struct drm_encoder *partner;
- int or = nv_encoder->or;
-
- 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->dcb->or) {
- if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
- return;
+ if (nv_encoder->dcb->type == DCB_OUTPUT_DP &&
+ nv_encoder->dcb->or & (1 << or)) {
+ tmp = nv_rd32(device, NV50_SOR_DP_CTRL(or, link));
+ tmp &= ~NV50_SOR_DP_CTRL_ENABLED;
+ nv_wr32(device, NV50_SOR_DP_CTRL(or, link), tmp);
break;
}
}
-
- nv_call(disp->core, NV50_DISP_SOR_PWR + or, (mode == DRM_MODE_DPMS_ON));
-
- if (nv_encoder->dcb->type == DCB_OUTPUT_DP)
- nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, disp->core);
-}
-
-static bool
-nv50_sor_mode_fixup(struct drm_encoder *encoder,
- const 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
-nv50_sor_disconnect(struct drm_encoder *encoder)
+nv50_display_unk40_handler(struct drm_device *dev)
{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nv50_mast *mast = nv50_mast(encoder->dev);
- const int or = nv_encoder->or;
- u32 *push;
-
- if (nv_encoder->crtc) {
- nv50_crtc_prepare(nv_encoder->crtc);
-
- push = evo_wait(mast, 4);
- if (push) {
- if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
- evo_mthd(push, 0x0600 + (or * 0x40), 1);
- evo_data(push, 0x00000000);
- } else {
- evo_mthd(push, 0x0200 + (or * 0x20), 1);
- evo_data(push, 0x00000000);
- }
-
- evo_mthd(push, 0x0080, 1);
- evo_data(push, 0x00000000);
- evo_kick(push, mast);
- }
-
- nv50_hdmi_disconnect(encoder);
- }
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nv50_display *disp = nv50_display(dev);
+ struct dcb_output *dcb = disp->irq.dcb;
+ u16 script = disp->irq.script;
+ u32 unk30 = nv_rd32(device, 0x610030), pclk = disp->irq.pclk;
- nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
- nv_encoder->crtc = NULL;
-}
+ NV_DEBUG(drm, "0x610030: 0x%08x\n", unk30);
+ disp->irq.dcb = NULL;
+ if (!dcb)
+ goto ack;
-static void
-nv50_sor_prepare(struct drm_encoder *encoder)
-{
- nv50_sor_disconnect(encoder);
- if (nouveau_encoder(encoder)->dcb->type == DCB_OUTPUT_DP)
- evo_sync(encoder->dev);
-}
+ nouveau_bios_run_display_table(dev, script, -pclk, dcb, -1);
+ nv50_display_unk40_dp_set_tmds(dev, dcb);
-static void
-nv50_sor_commit(struct drm_encoder *encoder)
-{
+ack:
+ nv_wr32(device, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40);
+ nv_wr32(device, 0x610030, 0x80000000);
+ nv_wr32(device, 0x619494, nv_rd32(device, 0x619494) | 8);
}
static void
-nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
- struct drm_display_mode *mode)
+nv50_display_bh(unsigned long data)
{
- struct nv50_disp *disp = nv50_disp(encoder->dev);
- struct nv50_mast *mast = nv50_mast(encoder->dev);
- struct drm_device *dev = encoder->dev;
+ struct drm_device *dev = (struct drm_device *)data;
+ struct nouveau_device *device = nouveau_dev(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
- 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 = &drm->vbios;
- u32 *push, lvds = 0;
- u8 owner = 1 << nv_crtc->index;
- u8 proto = 0xf;
- u8 depth = 0x0;
-
- nv_connector = nouveau_encoder_connector_get(nv_encoder);
- switch (nv_encoder->dcb->type) {
- case DCB_OUTPUT_TMDS:
- if (nv_encoder->dcb->sorconf.link & 1) {
- if (mode->clock < 165000)
- proto = 0x1;
- else
- proto = 0x5;
- } else {
- proto = 0x2;
- }
- nv50_hdmi_mode_set(encoder, mode);
- break;
- case DCB_OUTPUT_LVDS:
- proto = 0x0;
+ for (;;) {
+ uint32_t intr0 = nv_rd32(device, NV50_PDISPLAY_INTR_0);
+ uint32_t intr1 = nv_rd32(device, NV50_PDISPLAY_INTR_1);
- if (bios->fp_no_ddc) {
- if (bios->fp.dual_link)
- lvds |= 0x0100;
- if (bios->fp.if_is_24bit)
- lvds |= 0x0200;
- } else {
- if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
- if (((u8 *)nv_connector->edid)[121] == 2)
- lvds |= 0x0100;
- } else
- if (mode->clock >= bios->fp.duallink_transition_clk) {
- lvds |= 0x0100;
- }
-
- if (lvds & 0x0100) {
- if (bios->fp.strapless_is_24bit & 2)
- lvds |= 0x0200;
- } else {
- if (bios->fp.strapless_is_24bit & 1)
- lvds |= 0x0200;
- }
+ NV_DEBUG(drm, "PDISPLAY_INTR_BH 0x%08x 0x%08x\n", intr0, intr1);
- if (nv_connector->base.display_info.bpc == 8)
- lvds |= 0x0200;
- }
-
- nv_call(disp->core, NV50_DISP_SOR_LVDS_SCRIPT + nv_encoder->or, lvds);
- break;
- case DCB_OUTPUT_DP:
- if (nv_connector->base.display_info.bpc == 6) {
- nv_encoder->dp.datarate = mode->clock * 18 / 8;
- depth = 0x2;
- } else
- if (nv_connector->base.display_info.bpc == 8) {
- nv_encoder->dp.datarate = mode->clock * 24 / 8;
- depth = 0x5;
- } else {
- nv_encoder->dp.datarate = mode->clock * 30 / 8;
- depth = 0x6;
- }
-
- if (nv_encoder->dcb->sorconf.link & 1)
- proto = 0x8;
+ if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK10)
+ nv50_display_unk10_handler(dev);
else
- proto = 0x9;
- break;
- default:
- BUG_ON(1);
- break;
- }
-
- nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
-
- push = evo_wait(nv50_mast(dev), 8);
- if (push) {
- if (nv50_vers(mast) < NVD0_DISP_CLASS) {
- evo_mthd(push, 0x0600 + (nv_encoder->or * 0x040), 1);
- evo_data(push, (depth << 16) | (proto << 8) | owner);
- } else {
- u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
- u32 syncs = 0x00000001;
-
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- syncs |= 0x00000008;
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- syncs |= 0x00000010;
-
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- magic |= 0x00000001;
-
- evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
- evo_data(push, syncs | (depth << 6));
- evo_data(push, magic);
- evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 1);
- evo_data(push, owner | (proto << 8));
- }
-
- evo_kick(push, mast);
+ if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK20)
+ nv50_display_unk20_handler(dev);
+ else
+ if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK40)
+ nv50_display_unk40_handler(dev);
+ else
+ break;
}
- nv_encoder->crtc = encoder->crtc;
+ nv_wr32(device, NV03_PMC_INTR_EN_0, 1);
}
static void
-nv50_sor_destroy(struct drm_encoder *encoder)
+nv50_display_error_handler(struct drm_device *dev)
{
- drm_encoder_cleanup(encoder);
- kfree(encoder);
-}
-
-static const struct drm_encoder_helper_funcs nv50_sor_hfunc = {
- .dpms = nv50_sor_dpms,
- .mode_fixup = nv50_sor_mode_fixup,
- .prepare = nv50_sor_prepare,
- .commit = nv50_sor_commit,
- .mode_set = nv50_sor_mode_set,
- .disable = nv50_sor_disconnect,
- .get_crtc = nv50_display_crtc_get,
-};
-
-static const struct drm_encoder_funcs nv50_sor_func = {
- .destroy = nv50_sor_destroy,
-};
-
-static int
-nv50_sor_create(struct drm_connector *connector, struct dcb_output *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, &nv50_sor_func, DRM_MODE_ENCODER_TMDS);
- drm_encoder_helper_add(encoder, &nv50_sor_hfunc);
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ u32 channels = (nv_rd32(device, NV50_PDISPLAY_INTR_0) & 0x001f0000) >> 16;
+ u32 addr, data;
+ int chid;
- drm_mode_connector_attach_encoder(connector, encoder);
- return 0;
-}
+ for (chid = 0; chid < 5; chid++) {
+ if (!(channels & (1 << chid)))
+ continue;
-/******************************************************************************
- * Init
- *****************************************************************************/
-void
-nv50_display_fini(struct drm_device *dev)
-{
-}
+ nv_wr32(device, NV50_PDISPLAY_INTR_0, 0x00010000 << chid);
+ addr = nv_rd32(device, NV50_PDISPLAY_TRAPPED_ADDR(chid));
+ data = nv_rd32(device, NV50_PDISPLAY_TRAPPED_DATA(chid));
+ NV_ERROR(drm, "EvoCh %d Mthd 0x%04x Data 0x%08x "
+ "(0x%04x 0x%02x)\n", chid,
+ addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf);
-int
-nv50_display_init(struct drm_device *dev)
-{
- u32 *push = evo_wait(nv50_mast(dev), 32);
- if (push) {
- evo_mthd(push, 0x0088, 1);
- evo_data(push, NvEvoSync);
- evo_kick(push, nv50_mast(dev));
- return evo_sync(dev);
+ nv_wr32(device, NV50_PDISPLAY_TRAPPED_ADDR(chid), 0x90000000);
}
-
- return -EBUSY;
}
void
-nv50_display_destroy(struct drm_device *dev)
-{
- struct nv50_disp *disp = nv50_disp(dev);
-
- nv50_dmac_destroy(disp->core, &disp->mast.base);
-
- nouveau_bo_unmap(disp->sync);
- if (disp->sync)
- nouveau_bo_unpin(disp->sync);
- nouveau_bo_ref(NULL, &disp->sync);
-
- nouveau_display(dev)->priv = NULL;
- kfree(disp);
-}
-
-int
-nv50_display_create(struct drm_device *dev)
+nv50_display_intr(struct drm_device *dev)
{
- static const u16 oclass[] = {
- NVE0_DISP_CLASS,
- NVD0_DISP_CLASS,
- NVA3_DISP_CLASS,
- NV94_DISP_CLASS,
- NVA0_DISP_CLASS,
- NV84_DISP_CLASS,
- NV50_DISP_CLASS,
- };
struct nouveau_device *device = nouveau_dev(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct dcb_table *dcb = &drm->vbios.dcb;
- struct drm_connector *connector, *tmp;
- struct nv50_disp *disp;
- struct dcb_output *dcbe;
- int crtcs, ret, i;
+ struct nv50_display *disp = nv50_display(dev);
+ uint32_t delayed = 0;
- disp = kzalloc(sizeof(*disp), GFP_KERNEL);
- if (!disp)
- return -ENOMEM;
+ while (nv_rd32(device, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
+ uint32_t intr0 = nv_rd32(device, NV50_PDISPLAY_INTR_0);
+ uint32_t intr1 = nv_rd32(device, NV50_PDISPLAY_INTR_1);
+ uint32_t clock;
- nouveau_display(dev)->priv = disp;
- nouveau_display(dev)->dtor = nv50_display_destroy;
- nouveau_display(dev)->init = nv50_display_init;
- nouveau_display(dev)->fini = nv50_display_fini;
+ NV_DEBUG(drm, "PDISPLAY_INTR 0x%08x 0x%08x\n", intr0, intr1);
- /* small shared memory area we use for notifiers and semaphores */
- ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
- 0, 0x0000, NULL, &disp->sync);
- if (!ret) {
- ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM);
- if (!ret) {
- ret = nouveau_bo_map(disp->sync);
- if (ret)
- nouveau_bo_unpin(disp->sync);
- }
- if (ret)
- nouveau_bo_ref(NULL, &disp->sync);
- }
-
- if (ret)
- goto out;
-
- /* attempt to allocate a supported evo display class */
- ret = -ENODEV;
- for (i = 0; ret && i < ARRAY_SIZE(oclass); i++) {
- ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE,
- 0xd1500000, oclass[i], NULL, 0,
- &disp->core);
- }
-
- if (ret)
- goto out;
-
- /* allocate master evo channel */
- ret = nv50_dmac_create(disp->core, NV50_DISP_MAST_CLASS, 0,
- &(struct nv50_display_mast_class) {
- .pushbuf = EVO_PUSH_HANDLE(MAST, 0),
- }, sizeof(struct nv50_display_mast_class),
- disp->sync->bo.offset, &disp->mast.base);
- if (ret)
- goto out;
-
- /* create crtc objects to represent the hw heads */
- if (nv_mclass(disp->core) >= NVD0_DISP_CLASS)
- crtcs = nv_rd32(device, 0x022448);
- else
- crtcs = 2;
-
- for (i = 0; i < crtcs; i++) {
- ret = nv50_crtc_create(dev, disp->core, i);
- if (ret)
- goto out;
- }
+ if (!intr0 && !(intr1 & ~delayed))
+ break;
- /* 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 (intr0 & 0x001f0000) {
+ nv50_display_error_handler(dev);
+ intr0 &= ~0x001f0000;
+ }
- if (dcbe->location != DCB_LOC_ON_CHIP) {
- NV_WARN(drm, "skipping off-chip encoder %d/%d\n",
- dcbe->type, ffs(dcbe->or) - 1);
- continue;
+ if (intr1 & NV50_PDISPLAY_INTR_1_VBLANK_CRTC) {
+ intr1 &= ~NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
+ delayed |= NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
}
- switch (dcbe->type) {
- case DCB_OUTPUT_TMDS:
- case DCB_OUTPUT_LVDS:
- case DCB_OUTPUT_DP:
- nv50_sor_create(connector, dcbe);
- break;
- case DCB_OUTPUT_ANALOG:
- nv50_dac_create(connector, dcbe);
- break;
- default:
- NV_WARN(drm, "skipping unsupported encoder %d/%d\n",
- dcbe->type, ffs(dcbe->or) - 1);
- continue;
+ clock = (intr1 & (NV50_PDISPLAY_INTR_1_CLK_UNK10 |
+ NV50_PDISPLAY_INTR_1_CLK_UNK20 |
+ NV50_PDISPLAY_INTR_1_CLK_UNK40));
+ if (clock) {
+ nv_wr32(device, NV03_PMC_INTR_EN_0, 0);
+ tasklet_schedule(&disp->tasklet);
+ delayed |= clock;
+ intr1 &= ~clock;
}
- }
- /* 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;
+ if (intr0) {
+ NV_ERROR(drm, "unknown PDISPLAY_INTR_0: 0x%08x\n", intr0);
+ nv_wr32(device, NV50_PDISPLAY_INTR_0, intr0);
+ }
- NV_WARN(drm, "%s has no encoders, removing\n",
- drm_get_connector_name(connector));
- connector->funcs->destroy(connector);
+ if (intr1) {
+ NV_ERROR(drm,
+ "unknown PDISPLAY_INTR_1: 0x%08x\n", intr1);
+ nv_wr32(device, NV50_PDISPLAY_INTR_1, intr1);
+ }
}
-
-out:
- if (ret)
- nv50_display_destroy(dev);
- return ret;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_display.h b/trunk/drivers/gpu/drm/nouveau/nv50_display.h
index 70da347aa8c5..973554d8a7a6 100644
--- a/trunk/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_display.h
@@ -30,16 +30,77 @@
#include "nouveau_display.h"
#include "nouveau_crtc.h"
#include "nouveau_reg.h"
+#include "nv50_evo.h"
-int nv50_display_create(struct drm_device *);
-void nv50_display_destroy(struct drm_device *);
-int nv50_display_init(struct drm_device *);
-void nv50_display_fini(struct drm_device *);
+struct nv50_display_crtc {
+ struct nouveau_channel *sync;
+ struct {
+ struct nouveau_bo *bo;
+ u32 offset;
+ u16 value;
+ } sem;
+};
-void nv50_display_flip_stop(struct drm_crtc *);
+struct nv50_display {
+ struct nouveau_channel *master;
+
+ struct nouveau_gpuobj *ramin;
+ u32 dmao;
+ u32 hash;
+
+ struct nv50_display_crtc crtc[2];
+
+ struct tasklet_struct tasklet;
+ struct {
+ struct dcb_output *dcb;
+ u16 script;
+ u32 pclk;
+ } irq;
+};
+
+static inline struct nv50_display *
+nv50_display(struct drm_device *dev)
+{
+ return nouveau_display(dev)->priv;
+}
+
+int nv50_display_early_init(struct drm_device *dev);
+void nv50_display_late_takedown(struct drm_device *dev);
+int nv50_display_create(struct drm_device *dev);
+int nv50_display_init(struct drm_device *dev);
+void nv50_display_fini(struct drm_device *dev);
+void nv50_display_destroy(struct drm_device *dev);
+void nv50_display_intr(struct drm_device *);
+int nv50_crtc_blank(struct nouveau_crtc *, bool blank);
+int nv50_crtc_set_clock(struct drm_device *, int head, int pclk);
+
+u32 nv50_display_active_crtcs(struct drm_device *);
+
+int nv50_display_sync(struct drm_device *);
int nv50_display_flip_next(struct drm_crtc *, struct drm_framebuffer *,
+ struct nouveau_channel *chan);
+void nv50_display_flip_stop(struct drm_crtc *);
+
+int nv50_evo_create(struct drm_device *dev);
+void nv50_evo_destroy(struct drm_device *dev);
+int nv50_evo_init(struct drm_device *dev);
+void nv50_evo_fini(struct drm_device *dev);
+void nv50_evo_dmaobj_init(struct nouveau_gpuobj *, u32 memtype, u64 base,
+ u64 size);
+int nv50_evo_dmaobj_new(struct nouveau_channel *, u32 handle, u32 memtype,
+ u64 base, u64 size, struct nouveau_gpuobj **);
+
+int nvd0_display_create(struct drm_device *);
+void nvd0_display_destroy(struct drm_device *);
+int nvd0_display_init(struct drm_device *);
+void nvd0_display_fini(struct drm_device *);
+void nvd0_display_intr(struct drm_device *);
+
+void nvd0_display_flip_stop(struct drm_crtc *);
+int nvd0_display_flip_next(struct drm_crtc *, struct drm_framebuffer *,
struct nouveau_channel *, u32 swap_interval);
struct nouveau_bo *nv50_display_crtc_sema(struct drm_device *, int head);
+struct nouveau_bo *nvd0_display_crtc_sema(struct drm_device *, int head);
#endif /* __NV50_DISPLAY_H__ */
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_evo.c b/trunk/drivers/gpu/drm/nouveau/nv50_evo.c
new file mode 100644
index 000000000000..9f6f55cdfa77
--- /dev/null
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_evo.c
@@ -0,0 +1,403 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include
+
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
+#include "nv50_display.h"
+
+#include
+
+#include
+#include
+
+static u32
+nv50_evo_rd32(struct nouveau_object *object, u32 addr)
+{
+ void __iomem *iomem = object->oclass->ofuncs->rd08;
+ return ioread32_native(iomem + addr);
+}
+
+static void
+nv50_evo_wr32(struct nouveau_object *object, u32 addr, u32 data)
+{
+ void __iomem *iomem = object->oclass->ofuncs->rd08;
+ iowrite32_native(data, iomem + addr);
+}
+
+static void
+nv50_evo_channel_del(struct nouveau_channel **pevo)
+{
+ struct nouveau_channel *evo = *pevo;
+
+ if (!evo)
+ return;
+ *pevo = NULL;
+
+ nouveau_bo_unmap(evo->push.buffer);
+ nouveau_bo_ref(NULL, &evo->push.buffer);
+
+ if (evo->object)
+ iounmap(evo->object->oclass->ofuncs);
+
+ kfree(evo);
+}
+
+int
+nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 handle, u32 memtype,
+ u64 base, u64 size, struct nouveau_gpuobj **pobj)
+{
+ struct drm_device *dev = evo->fence;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nv50_display *disp = nv50_display(dev);
+ u32 dmao = disp->dmao;
+ u32 hash = disp->hash;
+ u32 flags5;
+
+ if (nv_device(drm->device)->chipset < 0xc0) {
+ /* not supported on 0x50, specified in format mthd */
+ if (nv_device(drm->device)->chipset == 0x50)
+ memtype = 0;
+ flags5 = 0x00010000;
+ } else {
+ if (memtype & 0x80000000)
+ flags5 = 0x00000000; /* large pages */
+ else
+ flags5 = 0x00020000;
+ }
+
+ nv_wo32(disp->ramin, dmao + 0x00, 0x0019003d | (memtype << 22));
+ nv_wo32(disp->ramin, dmao + 0x04, lower_32_bits(base + size - 1));
+ nv_wo32(disp->ramin, dmao + 0x08, lower_32_bits(base));
+ nv_wo32(disp->ramin, dmao + 0x0c, upper_32_bits(base + size - 1) << 24 |
+ upper_32_bits(base));
+ nv_wo32(disp->ramin, dmao + 0x10, 0x00000000);
+ nv_wo32(disp->ramin, dmao + 0x14, flags5);
+
+ nv_wo32(disp->ramin, hash + 0x00, handle);
+ nv_wo32(disp->ramin, hash + 0x04, (evo->handle << 28) | (dmao << 10) |
+ evo->handle);
+
+ disp->dmao += 0x20;
+ disp->hash += 0x08;
+ return 0;
+}
+
+static int
+nv50_evo_channel_new(struct drm_device *dev, int chid,
+ struct nouveau_channel **pevo)
+{
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nv50_display *disp = nv50_display(dev);
+ struct nouveau_channel *evo;
+ int ret;
+
+ evo = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL);
+ if (!evo)
+ return -ENOMEM;
+ *pevo = evo;
+
+ evo->drm = drm;
+ evo->handle = chid;
+ evo->fence = dev;
+ evo->user_get = 4;
+ evo->user_put = 0;
+
+ ret = nouveau_bo_new(dev, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, NULL,
+ &evo->push.buffer);
+ if (ret == 0)
+ ret = nouveau_bo_pin(evo->push.buffer, TTM_PL_FLAG_VRAM);
+ if (ret) {
+ NV_ERROR(drm, "Error creating EVO DMA push buffer: %d\n", ret);
+ nv50_evo_channel_del(pevo);
+ return ret;
+ }
+
+ ret = nouveau_bo_map(evo->push.buffer);
+ if (ret) {
+ NV_ERROR(drm, "Error mapping EVO DMA push buffer: %d\n", ret);
+ nv50_evo_channel_del(pevo);
+ return ret;
+ }
+
+ evo->object = kzalloc(sizeof(*evo->object), GFP_KERNEL);
+#ifdef NOUVEAU_OBJECT_MAGIC
+ evo->object->_magic = NOUVEAU_OBJECT_MAGIC;
+#endif
+ evo->object->parent = nv_object(disp->ramin)->parent;
+ evo->object->engine = nv_object(disp->ramin)->engine;
+ evo->object->oclass =
+ kzalloc(sizeof(*evo->object->oclass), GFP_KERNEL);
+ evo->object->oclass->ofuncs =
+ kzalloc(sizeof(*evo->object->oclass->ofuncs), GFP_KERNEL);
+ evo->object->oclass->ofuncs->rd32 = nv50_evo_rd32;
+ evo->object->oclass->ofuncs->wr32 = nv50_evo_wr32;
+ evo->object->oclass->ofuncs->rd08 =
+ ioremap(pci_resource_start(dev->pdev, 0) +
+ NV50_PDISPLAY_USER(evo->handle), PAGE_SIZE);
+ return 0;
+}
+
+static int
+nv50_evo_channel_init(struct nouveau_channel *evo)
+{
+ struct nouveau_drm *drm = evo->drm;
+ struct nouveau_device *device = nv_device(drm->device);
+ int id = evo->handle, ret, i;
+ u64 pushbuf = evo->push.buffer->bo.offset;
+ u32 tmp;
+
+ tmp = nv_rd32(device, NV50_PDISPLAY_EVO_CTRL(id));
+ if ((tmp & 0x009f0000) == 0x00020000)
+ nv_wr32(device, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00800000);
+
+ tmp = nv_rd32(device, NV50_PDISPLAY_EVO_CTRL(id));
+ if ((tmp & 0x003f0000) == 0x00030000)
+ nv_wr32(device, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00600000);
+
+ /* initialise fifo */
+ nv_wr32(device, NV50_PDISPLAY_EVO_DMA_CB(id), pushbuf >> 8 |
+ NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM |
+ NV50_PDISPLAY_EVO_DMA_CB_VALID);
+ nv_wr32(device, NV50_PDISPLAY_EVO_UNK2(id), 0x00010000);
+ nv_wr32(device, NV50_PDISPLAY_EVO_HASH_TAG(id), id);
+ nv_mask(device, NV50_PDISPLAY_EVO_CTRL(id), NV50_PDISPLAY_EVO_CTRL_DMA,
+ NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED);
+
+ nv_wr32(device, NV50_PDISPLAY_USER_PUT(id), 0x00000000);
+ nv_wr32(device, NV50_PDISPLAY_EVO_CTRL(id), 0x01000003 |
+ NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED);
+ if (!nv_wait(device, NV50_PDISPLAY_EVO_CTRL(id), 0x80000000, 0x00000000)) {
+ NV_ERROR(drm, "EvoCh %d init timeout: 0x%08x\n", id,
+ nv_rd32(device, NV50_PDISPLAY_EVO_CTRL(id)));
+ return -EBUSY;
+ }
+
+ /* enable error reporting on the channel */
+ nv_mask(device, 0x610028, 0x00000000, 0x00010001 << id);
+
+ evo->dma.max = (4096/4) - 2;
+ evo->dma.max &= ~7;
+ evo->dma.put = 0;
+ evo->dma.cur = evo->dma.put;
+ evo->dma.free = evo->dma.max - evo->dma.cur;
+
+ ret = RING_SPACE(evo, NOUVEAU_DMA_SKIPS);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
+ OUT_RING(evo, 0);
+
+ return 0;
+}
+
+static void
+nv50_evo_channel_fini(struct nouveau_channel *evo)
+{
+ struct nouveau_drm *drm = evo->drm;
+ struct nouveau_device *device = nv_device(drm->device);
+ int id = evo->handle;
+
+ nv_mask(device, 0x610028, 0x00010001 << id, 0x00000000);
+ nv_mask(device, NV50_PDISPLAY_EVO_CTRL(id), 0x00001010, 0x00001000);
+ nv_wr32(device, NV50_PDISPLAY_INTR_0, (1 << id));
+ nv_mask(device, NV50_PDISPLAY_EVO_CTRL(id), 0x00000003, 0x00000000);
+ if (!nv_wait(device, NV50_PDISPLAY_EVO_CTRL(id), 0x001e0000, 0x00000000)) {
+ NV_ERROR(drm, "EvoCh %d takedown timeout: 0x%08x\n", id,
+ nv_rd32(device, NV50_PDISPLAY_EVO_CTRL(id)));
+ }
+}
+
+void
+nv50_evo_destroy(struct drm_device *dev)
+{
+ struct nv50_display *disp = nv50_display(dev);
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (disp->crtc[i].sem.bo) {
+ nouveau_bo_unmap(disp->crtc[i].sem.bo);
+ nouveau_bo_ref(NULL, &disp->crtc[i].sem.bo);
+ }
+ nv50_evo_channel_del(&disp->crtc[i].sync);
+ }
+ nv50_evo_channel_del(&disp->master);
+ nouveau_gpuobj_ref(NULL, &disp->ramin);
+}
+
+int
+nv50_evo_create(struct drm_device *dev)
+{
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_fb *pfb = nouveau_fb(drm->device);
+ struct nv50_display *disp = nv50_display(dev);
+ struct nouveau_channel *evo;
+ int ret, i, j;
+
+ /* setup object management on it, any other evo channel will
+ * use this also as there's no per-channel support on the
+ * hardware
+ */
+ ret = nouveau_gpuobj_new(drm->device, NULL, 32768, 65536,
+ NVOBJ_FLAG_ZERO_ALLOC, &disp->ramin);
+ if (ret) {
+ NV_ERROR(drm, "Error allocating EVO channel memory: %d\n", ret);
+ goto err;
+ }
+
+ disp->hash = 0x0000;
+ disp->dmao = 0x1000;
+
+ /* create primary evo channel, the one we use for modesetting
+ * purporses
+ */
+ ret = nv50_evo_channel_new(dev, 0, &disp->master);
+ if (ret)
+ return ret;
+ evo = disp->master;
+
+ ret = nv50_evo_dmaobj_new(disp->master, NvEvoSync, 0x0000,
+ disp->ramin->addr + 0x2000, 0x1000, NULL);
+ if (ret)
+ goto err;
+
+ /* create some default objects for the scanout memtypes we support */
+ ret = nv50_evo_dmaobj_new(disp->master, NvEvoVRAM, 0x0000,
+ 0, pfb->ram.size, NULL);
+ if (ret)
+ goto err;
+
+ ret = nv50_evo_dmaobj_new(disp->master, NvEvoVRAM_LP, 0x80000000,
+ 0, pfb->ram.size, NULL);
+ if (ret)
+ goto err;
+
+ ret = nv50_evo_dmaobj_new(disp->master, NvEvoFB32, 0x80000000 |
+ (nv_device(drm->device)->chipset < 0xc0 ? 0x7a : 0xfe),
+ 0, pfb->ram.size, NULL);
+ if (ret)
+ goto err;
+
+ ret = nv50_evo_dmaobj_new(disp->master, NvEvoFB16, 0x80000000 |
+ (nv_device(drm->device)->chipset < 0xc0 ? 0x70 : 0xfe),
+ 0, pfb->ram.size, NULL);
+ if (ret)
+ goto err;
+
+ /* create "display sync" channels and other structures we need
+ * to implement page flipping
+ */
+ for (i = 0; i < 2; i++) {
+ struct nv50_display_crtc *dispc = &disp->crtc[i];
+ u64 offset;
+
+ ret = nv50_evo_channel_new(dev, 1 + i, &dispc->sync);
+ if (ret)
+ goto err;
+
+ ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
+ 0, 0x0000, NULL, &dispc->sem.bo);
+ if (!ret) {
+ 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)
+ goto err;
+
+ ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoSync, 0x0000,
+ offset, 4096, NULL);
+ if (ret)
+ goto err;
+
+ ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoVRAM_LP, 0x80000000,
+ 0, pfb->ram.size, NULL);
+ if (ret)
+ goto err;
+
+ ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB32, 0x80000000 |
+ (nv_device(drm->device)->chipset < 0xc0 ?
+ 0x7a : 0xfe),
+ 0, pfb->ram.size, NULL);
+ if (ret)
+ goto err;
+
+ ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB16, 0x80000000 |
+ (nv_device(drm->device)->chipset < 0xc0 ?
+ 0x70 : 0xfe),
+ 0, pfb->ram.size, NULL);
+ if (ret)
+ goto err;
+
+ for (j = 0; j < 4096; j += 4)
+ nouveau_bo_wr32(dispc->sem.bo, j / 4, 0x74b1e000);
+ dispc->sem.offset = 0;
+ }
+
+ return 0;
+
+err:
+ nv50_evo_destroy(dev);
+ return ret;
+}
+
+int
+nv50_evo_init(struct drm_device *dev)
+{
+ struct nv50_display *disp = nv50_display(dev);
+ int ret, i;
+
+ ret = nv50_evo_channel_init(disp->master);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < 2; i++) {
+ ret = nv50_evo_channel_init(disp->crtc[i].sync);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void
+nv50_evo_fini(struct drm_device *dev)
+{
+ struct nv50_display *disp = nv50_display(dev);
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (disp->crtc[i].sync)
+ nv50_evo_channel_fini(disp->crtc[i].sync);
+ }
+
+ if (disp->master)
+ nv50_evo_channel_fini(disp->master);
+}
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_evo.h b/trunk/drivers/gpu/drm/nouveau/nv50_evo.h
new file mode 100644
index 000000000000..771d879bc834
--- /dev/null
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_evo.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2008 Maarten Maathuis.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __NV50_EVO_H__
+#define __NV50_EVO_H__
+
+#define NV50_EVO_UPDATE 0x00000080
+#define NV50_EVO_UNK84 0x00000084
+#define NV50_EVO_UNK84_NOTIFY 0x40000000
+#define NV50_EVO_UNK84_NOTIFY_DISABLED 0x00000000
+#define NV50_EVO_UNK84_NOTIFY_ENABLED 0x40000000
+#define NV50_EVO_DMA_NOTIFY 0x00000088
+#define NV50_EVO_DMA_NOTIFY_HANDLE 0xffffffff
+#define NV50_EVO_DMA_NOTIFY_HANDLE_NONE 0x00000000
+#define NV50_EVO_UNK8C 0x0000008C
+
+#define NV50_EVO_DAC(n, r) ((n) * 0x80 + NV50_EVO_DAC_##r)
+#define NV50_EVO_DAC_MODE_CTRL 0x00000400
+#define NV50_EVO_DAC_MODE_CTRL_CRTC0 0x00000001
+#define NV50_EVO_DAC_MODE_CTRL_CRTC1 0x00000002
+#define NV50_EVO_DAC_MODE_CTRL2 0x00000404
+#define NV50_EVO_DAC_MODE_CTRL2_NHSYNC 0x00000001
+#define NV50_EVO_DAC_MODE_CTRL2_NVSYNC 0x00000002
+
+#define NV50_EVO_SOR(n, r) ((n) * 0x40 + NV50_EVO_SOR_##r)
+#define NV50_EVO_SOR_MODE_CTRL 0x00000600
+#define NV50_EVO_SOR_MODE_CTRL_CRTC0 0x00000001
+#define NV50_EVO_SOR_MODE_CTRL_CRTC1 0x00000002
+#define NV50_EVO_SOR_MODE_CTRL_TMDS 0x00000100
+#define NV50_EVO_SOR_MODE_CTRL_TMDS_DUAL_LINK 0x00000400
+#define NV50_EVO_SOR_MODE_CTRL_NHSYNC 0x00001000
+#define NV50_EVO_SOR_MODE_CTRL_NVSYNC 0x00002000
+
+#define NV50_EVO_CRTC(n, r) ((n) * 0x400 + NV50_EVO_CRTC_##r)
+#define NV84_EVO_CRTC(n, r) ((n) * 0x400 + NV84_EVO_CRTC_##r)
+#define NV50_EVO_CRTC_UNK0800 0x00000800
+#define NV50_EVO_CRTC_CLOCK 0x00000804
+#define NV50_EVO_CRTC_INTERLACE 0x00000808
+#define NV50_EVO_CRTC_DISPLAY_START 0x00000810
+#define NV50_EVO_CRTC_DISPLAY_TOTAL 0x00000814
+#define NV50_EVO_CRTC_SYNC_DURATION 0x00000818
+#define NV50_EVO_CRTC_SYNC_START_TO_BLANK_END 0x0000081c
+#define NV50_EVO_CRTC_UNK0820 0x00000820
+#define NV50_EVO_CRTC_UNK0824 0x00000824
+#define NV50_EVO_CRTC_UNK082C 0x0000082c
+#define NV50_EVO_CRTC_CLUT_MODE 0x00000840
+/* You can't have a palette in 8 bit mode (=OFF) */
+#define NV50_EVO_CRTC_CLUT_MODE_BLANK 0x00000000
+#define NV50_EVO_CRTC_CLUT_MODE_OFF 0x80000000
+#define NV50_EVO_CRTC_CLUT_MODE_ON 0xC0000000
+#define NV50_EVO_CRTC_CLUT_OFFSET 0x00000844
+#define NV84_EVO_CRTC_CLUT_DMA 0x0000085C
+#define NV84_EVO_CRTC_CLUT_DMA_HANDLE 0xffffffff
+#define NV84_EVO_CRTC_CLUT_DMA_HANDLE_NONE 0x00000000
+#define NV50_EVO_CRTC_FB_OFFSET 0x00000860
+#define NV50_EVO_CRTC_FB_SIZE 0x00000868
+#define NV50_EVO_CRTC_FB_CONFIG 0x0000086c
+#define NV50_EVO_CRTC_FB_CONFIG_MODE 0x00100000
+#define NV50_EVO_CRTC_FB_CONFIG_MODE_TILE 0x00000000
+#define NV50_EVO_CRTC_FB_CONFIG_MODE_PITCH 0x00100000
+#define NV50_EVO_CRTC_FB_DEPTH 0x00000870
+#define NV50_EVO_CRTC_FB_DEPTH_8 0x00001e00
+#define NV50_EVO_CRTC_FB_DEPTH_15 0x0000e900
+#define NV50_EVO_CRTC_FB_DEPTH_16 0x0000e800
+#define NV50_EVO_CRTC_FB_DEPTH_24 0x0000cf00
+#define NV50_EVO_CRTC_FB_DEPTH_30 0x0000d100
+#define NV50_EVO_CRTC_FB_DMA 0x00000874
+#define NV50_EVO_CRTC_FB_DMA_HANDLE 0xffffffff
+#define NV50_EVO_CRTC_FB_DMA_HANDLE_NONE 0x00000000
+#define NV50_EVO_CRTC_CURSOR_CTRL 0x00000880
+#define NV50_EVO_CRTC_CURSOR_CTRL_HIDE 0x05000000
+#define NV50_EVO_CRTC_CURSOR_CTRL_SHOW 0x85000000
+#define NV50_EVO_CRTC_CURSOR_OFFSET 0x00000884
+#define NV84_EVO_CRTC_CURSOR_DMA 0x0000089c
+#define NV84_EVO_CRTC_CURSOR_DMA_HANDLE 0xffffffff
+#define NV84_EVO_CRTC_CURSOR_DMA_HANDLE_NONE 0x00000000
+#define NV50_EVO_CRTC_DITHER_CTRL 0x000008a0
+#define NV50_EVO_CRTC_DITHER_CTRL_OFF 0x00000000
+#define NV50_EVO_CRTC_DITHER_CTRL_ON 0x00000011
+#define NV50_EVO_CRTC_SCALE_CTRL 0x000008a4
+#define NV50_EVO_CRTC_SCALE_CTRL_INACTIVE 0x00000000
+#define NV50_EVO_CRTC_SCALE_CTRL_ACTIVE 0x00000009
+#define NV50_EVO_CRTC_COLOR_CTRL 0x000008a8
+#define NV50_EVO_CRTC_COLOR_CTRL_VIBRANCE 0x000fff00
+#define NV50_EVO_CRTC_COLOR_CTRL_HUE 0xfff00000
+#define NV50_EVO_CRTC_FB_POS 0x000008c0
+#define NV50_EVO_CRTC_REAL_RES 0x000008c8
+#define NV50_EVO_CRTC_SCALE_CENTER_OFFSET 0x000008d4
+#define NV50_EVO_CRTC_SCALE_CENTER_OFFSET_VAL(x, y) \
+ ((((unsigned)y << 16) & 0xFFFF0000) | (((unsigned)x) & 0x0000FFFF))
+/* Both of these are needed, otherwise nothing happens. */
+#define NV50_EVO_CRTC_SCALE_RES1 0x000008d8
+#define NV50_EVO_CRTC_SCALE_RES2 0x000008dc
+#define NV50_EVO_CRTC_UNK900 0x00000900
+#define NV50_EVO_CRTC_UNK904 0x00000904
+
+#endif
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_fence.c b/trunk/drivers/gpu/drm/nouveau/nv50_fence.c
index c20f2727ea0b..e0763ea88ee2 100644
--- a/trunk/drivers/gpu/drm/nouveau/nv50_fence.c
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_fence.c
@@ -110,11 +110,8 @@ nv50_fence_create(struct nouveau_drm *drm)
0, 0x0000, NULL, &priv->bo);
if (!ret) {
ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
- if (!ret) {
+ if (!ret)
ret = nouveau_bo_map(priv->bo);
- if (ret)
- nouveau_bo_unpin(priv->bo);
- }
if (ret)
nouveau_bo_ref(NULL, &priv->bo);
}
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_pm.c b/trunk/drivers/gpu/drm/nouveau/nv50_pm.c
index 8bd5d2781baf..c4a65039b1ca 100644
--- a/trunk/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -546,7 +546,7 @@ calc_mclk(struct drm_device *dev, struct nouveau_pm_level *perflvl,
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_device *device = nouveau_dev(dev);
- u32 crtc_mask = 0; /*XXX: nv50_display_active_crtcs(dev); */
+ u32 crtc_mask = nv50_display_active_crtcs(dev);
struct nouveau_mem_exec_func exec = {
.dev = dev,
.precharge = mclk_precharge,
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_sor.c b/trunk/drivers/gpu/drm/nouveau/nv50_sor.c
new file mode 100644
index 000000000000..b562b59e1326
--- /dev/null
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -0,0 +1,530 @@
+/*
+ * Copyright (C) 2008 Maarten Maathuis.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include
+#include
+
+#define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
+#include "nouveau_reg.h"
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
+#include "nouveau_encoder.h"
+#include "nouveau_connector.h"
+#include "nouveau_crtc.h"
+#include "nv50_display.h"
+
+#include
+
+static u32
+nv50_sor_dp_lane_map(struct drm_device *dev, struct dcb_output *dcb, u8 lane)
+{
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ static const u8 nvaf[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
+ static const u8 nv50[] = { 16, 8, 0, 24 };
+ if (nv_device(drm->device)->chipset == 0xaf)
+ return nvaf[lane];
+ return nv50[lane];
+}
+
+static void
+nv50_sor_dp_train_set(struct drm_device *dev, struct dcb_output *dcb, u8 pattern)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ nv_mask(device, NV50_SOR_DP_CTRL(or, link), 0x0f000000, pattern << 24);
+}
+
+static void
+nv50_sor_dp_train_adj(struct drm_device *dev, struct dcb_output *dcb,
+ u8 lane, u8 swing, u8 preem)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ u32 shift = nv50_sor_dp_lane_map(dev, dcb, lane);
+ u32 mask = 0x000000ff << shift;
+ u8 *table, *entry, *config;
+
+ table = nouveau_dp_bios_data(dev, dcb, &entry);
+ if (!table || (table[0] != 0x20 && table[0] != 0x21)) {
+ NV_ERROR(drm, "PDISP: unsupported DP table for chipset\n");
+ return;
+ }
+
+ config = entry + table[4];
+ while (config[0] != swing || config[1] != preem) {
+ config += table[5];
+ if (config >= entry + table[4] + entry[4] * table[5])
+ return;
+ }
+
+ nv_mask(device, NV50_SOR_DP_UNK118(or, link), mask, config[2] << shift);
+ nv_mask(device, NV50_SOR_DP_UNK120(or, link), mask, config[3] << shift);
+ nv_mask(device, NV50_SOR_DP_UNK130(or, link), 0x0000ff00, config[4] << 8);
+}
+
+static void
+nv50_sor_dp_link_set(struct drm_device *dev, struct dcb_output *dcb, int crtc,
+ int link_nr, u32 link_bw, bool enhframe)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ u32 dpctrl = nv_rd32(device, NV50_SOR_DP_CTRL(or, link)) & ~0x001f4000;
+ u32 clksor = nv_rd32(device, 0x614300 + (or * 0x800)) & ~0x000c0000;
+ u8 *table, *entry, mask;
+ int i;
+
+ table = nouveau_dp_bios_data(dev, dcb, &entry);
+ if (!table || (table[0] != 0x20 && table[0] != 0x21)) {
+ NV_ERROR(drm, "PDISP: unsupported DP table for chipset\n");
+ return;
+ }
+
+ entry = ROMPTR(dev, entry[10]);
+ if (entry) {
+ while (link_bw < ROM16(entry[0]) * 10)
+ entry += 4;
+
+ nouveau_bios_run_init_table(dev, ROM16(entry[2]), dcb, crtc);
+ }
+
+ dpctrl |= ((1 << link_nr) - 1) << 16;
+ if (enhframe)
+ dpctrl |= 0x00004000;
+
+ if (link_bw > 162000)
+ clksor |= 0x00040000;
+
+ nv_wr32(device, 0x614300 + (or * 0x800), clksor);
+ nv_wr32(device, NV50_SOR_DP_CTRL(or, link), dpctrl);
+
+ mask = 0;
+ for (i = 0; i < link_nr; i++)
+ mask |= 1 << (nv50_sor_dp_lane_map(dev, dcb, i) >> 3);
+ nv_mask(device, NV50_SOR_DP_UNK130(or, link), 0x0000000f, mask);
+}
+
+static void
+nv50_sor_dp_link_get(struct drm_device *dev, u32 or, u32 link, u32 *nr, u32 *bw)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ u32 dpctrl = nv_rd32(device, NV50_SOR_DP_CTRL(or, link)) & 0x000f0000;
+ u32 clksor = nv_rd32(device, 0x614300 + (or * 0x800));
+ if (clksor & 0x000c0000)
+ *bw = 270000;
+ else
+ *bw = 162000;
+
+ if (dpctrl > 0x00030000) *nr = 4;
+ else if (dpctrl > 0x00010000) *nr = 2;
+ else *nr = 1;
+}
+
+void
+nv50_sor_dp_calc_tu(struct drm_device *dev, int or, int link, u32 clk, u32 bpp)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ const u32 symbol = 100000;
+ int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
+ int TU, VTUi, VTUf, VTUa;
+ u64 link_data_rate, link_ratio, unk;
+ u32 best_diff = 64 * symbol;
+ u32 link_nr, link_bw, r;
+
+ /* calculate packed data rate for each lane */
+ nv50_sor_dp_link_get(dev, or, link, &link_nr, &link_bw);
+ link_data_rate = (clk * bpp / 8) / link_nr;
+
+ /* calculate ratio of packed data rate to link symbol rate */
+ link_ratio = link_data_rate * symbol;
+ r = do_div(link_ratio, link_bw);
+
+ for (TU = 64; TU >= 32; TU--) {
+ /* calculate average number of valid symbols in each TU */
+ u32 tu_valid = link_ratio * TU;
+ u32 calc, diff;
+
+ /* find a hw representation for the fraction.. */
+ VTUi = tu_valid / symbol;
+ calc = VTUi * symbol;
+ diff = tu_valid - calc;
+ if (diff) {
+ if (diff >= (symbol / 2)) {
+ VTUf = symbol / (symbol - diff);
+ if (symbol - (VTUf * diff))
+ VTUf++;
+
+ if (VTUf <= 15) {
+ VTUa = 1;
+ calc += symbol - (symbol / VTUf);
+ } else {
+ VTUa = 0;
+ VTUf = 1;
+ calc += symbol;
+ }
+ } else {
+ VTUa = 0;
+ VTUf = min((int)(symbol / diff), 15);
+ calc += symbol / VTUf;
+ }
+
+ diff = calc - tu_valid;
+ } else {
+ /* no remainder, but the hw doesn't like the fractional
+ * part to be zero. decrement the integer part and
+ * have the fraction add a whole symbol back
+ */
+ VTUa = 0;
+ VTUf = 1;
+ VTUi--;
+ }
+
+ if (diff < best_diff) {
+ best_diff = diff;
+ bestTU = TU;
+ bestVTUa = VTUa;
+ bestVTUf = VTUf;
+ bestVTUi = VTUi;
+ if (diff == 0)
+ break;
+ }
+ }
+
+ if (!bestTU) {
+ NV_ERROR(drm, "DP: unable to find suitable config\n");
+ return;
+ }
+
+ /* XXX close to vbios numbers, but not right */
+ unk = (symbol - link_ratio) * bestTU;
+ unk *= link_ratio;
+ r = do_div(unk, symbol);
+ r = do_div(unk, symbol);
+ unk += 6;
+
+ nv_mask(device, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2);
+ nv_mask(device, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 |
+ bestVTUf << 16 |
+ bestVTUi << 8 |
+ unk);
+}
+static void
+nv50_sor_disconnect(struct drm_encoder *encoder)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ struct drm_device *dev = encoder->dev;
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ int ret;
+
+ if (!nv_encoder->crtc)
+ return;
+ nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
+
+ NV_DEBUG(drm, "Disconnecting SOR %d\n", nv_encoder->or);
+
+ ret = RING_SPACE(evo, 4);
+ if (ret) {
+ NV_ERROR(drm, "no space while disconnecting SOR\n");
+ return;
+ }
+ BEGIN_NV04(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
+ OUT_RING (evo, 0);
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING (evo, 0);
+
+ nouveau_hdmi_mode_set(encoder, NULL);
+
+ nv_encoder->crtc = NULL;
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
+}
+
+static void
+nv50_sor_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct nouveau_device *device = nouveau_dev(encoder->dev);
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ struct drm_device *dev = encoder->dev;
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct drm_encoder *enc;
+ uint32_t val;
+ int or = nv_encoder->or;
+
+ NV_DEBUG(drm, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode);
+
+ nv_encoder->last_dpms = mode;
+ list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
+ struct nouveau_encoder *nvenc = nouveau_encoder(enc);
+
+ if (nvenc == nv_encoder ||
+ (nvenc->dcb->type != DCB_OUTPUT_TMDS &&
+ nvenc->dcb->type != DCB_OUTPUT_LVDS &&
+ nvenc->dcb->type != DCB_OUTPUT_DP) ||
+ nvenc->dcb->or != nv_encoder->dcb->or)
+ continue;
+
+ if (nvenc->last_dpms == DRM_MODE_DPMS_ON)
+ return;
+ }
+
+ /* wait for it to be done */
+ if (!nv_wait(device, NV50_PDISPLAY_SOR_DPMS_CTRL(or),
+ NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) {
+ NV_ERROR(drm, "timeout: SOR_DPMS_CTRL_PENDING(%d) == 0\n", or);
+ NV_ERROR(drm, "SOR_DPMS_CTRL(%d) = 0x%08x\n", or,
+ nv_rd32(device, NV50_PDISPLAY_SOR_DPMS_CTRL(or)));
+ }
+
+ val = nv_rd32(device, NV50_PDISPLAY_SOR_DPMS_CTRL(or));
+
+ if (mode == DRM_MODE_DPMS_ON)
+ val |= NV50_PDISPLAY_SOR_DPMS_CTRL_ON;
+ else
+ val &= ~NV50_PDISPLAY_SOR_DPMS_CTRL_ON;
+
+ nv_wr32(device, NV50_PDISPLAY_SOR_DPMS_CTRL(or), val |
+ NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING);
+ if (!nv_wait(device, NV50_PDISPLAY_SOR_DPMS_STATE(or),
+ NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
+ NV_ERROR(drm, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", or);
+ NV_ERROR(drm, "SOR_DPMS_STATE(%d) = 0x%08x\n", or,
+ nv_rd32(device, NV50_PDISPLAY_SOR_DPMS_STATE(or)));
+ }
+
+ if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
+ struct dp_train_func func = {
+ .link_set = nv50_sor_dp_link_set,
+ .train_set = nv50_sor_dp_train_set,
+ .train_adj = nv50_sor_dp_train_adj
+ };
+
+ nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, &func);
+ }
+}
+
+static void
+nv50_sor_save(struct drm_encoder *encoder)
+{
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ NV_ERROR(drm, "!!\n");
+}
+
+static void
+nv50_sor_restore(struct drm_encoder *encoder)
+{
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ NV_ERROR(drm, "!!\n");
+}
+
+static bool
+nv50_sor_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_connector *connector;
+
+ NV_DEBUG(drm, "or %d\n", nv_encoder->or);
+
+ connector = nouveau_encoder_connector_get(nv_encoder);
+ if (!connector) {
+ NV_ERROR(drm, "Encoder has no connector\n");
+ return false;
+ }
+
+ if (connector->scaling_mode != DRM_MODE_SCALE_NONE &&
+ connector->native_mode)
+ drm_mode_copy(adjusted_mode, connector->native_mode);
+
+ return true;
+}
+
+static void
+nv50_sor_prepare(struct drm_encoder *encoder)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ nv50_sor_disconnect(encoder);
+ if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
+ /* avoid race between link training and supervisor intr */
+ nv50_display_sync(encoder->dev);
+ }
+}
+
+static void
+nv50_sor_commit(struct drm_encoder *encoder)
+{
+}
+
+static void
+nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
+ struct drm_display_mode *mode)
+{
+ struct nouveau_channel *evo = nv50_display(encoder->dev)->master;
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+ struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc);
+ struct nouveau_connector *nv_connector;
+ uint32_t mode_ctl = 0;
+ int ret;
+
+ NV_DEBUG(drm, "or %d type %d -> crtc %d\n",
+ nv_encoder->or, nv_encoder->dcb->type, crtc->index);
+ nv_encoder->crtc = encoder->crtc;
+
+ switch (nv_encoder->dcb->type) {
+ case DCB_OUTPUT_TMDS:
+ if (nv_encoder->dcb->sorconf.link & 1) {
+ if (mode->clock < 165000)
+ mode_ctl = 0x0100;
+ else
+ mode_ctl = 0x0500;
+ } else
+ mode_ctl = 0x0200;
+
+ nouveau_hdmi_mode_set(encoder, mode);
+ break;
+ case DCB_OUTPUT_DP:
+ nv_connector = nouveau_encoder_connector_get(nv_encoder);
+ if (nv_connector && nv_connector->base.display_info.bpc == 6) {
+ nv_encoder->dp.datarate = mode->clock * 18 / 8;
+ mode_ctl |= 0x00020000;
+ } else {
+ nv_encoder->dp.datarate = mode->clock * 24 / 8;
+ mode_ctl |= 0x00050000;
+ }
+
+ if (nv_encoder->dcb->sorconf.link & 1)
+ mode_ctl |= 0x00000800;
+ else
+ mode_ctl |= 0x00000900;
+ break;
+ default:
+ break;
+ }
+
+ if (crtc->index == 1)
+ mode_ctl |= NV50_EVO_SOR_MODE_CTRL_CRTC1;
+ else
+ mode_ctl |= NV50_EVO_SOR_MODE_CTRL_CRTC0;
+
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ mode_ctl |= NV50_EVO_SOR_MODE_CTRL_NHSYNC;
+
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ mode_ctl |= NV50_EVO_SOR_MODE_CTRL_NVSYNC;
+
+ nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
+
+ ret = RING_SPACE(evo, 2);
+ if (ret) {
+ NV_ERROR(drm, "no space while connecting SOR\n");
+ nv_encoder->crtc = NULL;
+ return;
+ }
+ BEGIN_NV04(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
+ OUT_RING(evo, mode_ctl);
+}
+
+static struct drm_crtc *
+nv50_sor_crtc_get(struct drm_encoder *encoder)
+{
+ return nouveau_encoder(encoder)->crtc;
+}
+
+static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
+ .dpms = nv50_sor_dpms,
+ .save = nv50_sor_save,
+ .restore = nv50_sor_restore,
+ .mode_fixup = nv50_sor_mode_fixup,
+ .prepare = nv50_sor_prepare,
+ .commit = nv50_sor_commit,
+ .mode_set = nv50_sor_mode_set,
+ .get_crtc = nv50_sor_crtc_get,
+ .detect = NULL,
+ .disable = nv50_sor_disconnect
+};
+
+static void
+nv50_sor_destroy(struct drm_encoder *encoder)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_drm *drm = nouveau_drm(encoder->dev);
+
+ NV_DEBUG(drm, "\n");
+
+ drm_encoder_cleanup(encoder);
+
+ kfree(nv_encoder);
+}
+
+static const struct drm_encoder_funcs nv50_sor_encoder_funcs = {
+ .destroy = nv50_sor_destroy,
+};
+
+int
+nv50_sor_create(struct drm_connector *connector, struct dcb_output *entry)
+{
+ struct nouveau_encoder *nv_encoder = NULL;
+ struct drm_device *dev = connector->dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct drm_encoder *encoder;
+ int type;
+
+ NV_DEBUG(drm, "\n");
+
+ switch (entry->type) {
+ case DCB_OUTPUT_TMDS:
+ case DCB_OUTPUT_DP:
+ type = DRM_MODE_ENCODER_TMDS;
+ break;
+ case DCB_OUTPUT_LVDS:
+ type = DRM_MODE_ENCODER_LVDS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
+ if (!nv_encoder)
+ return -ENOMEM;
+ encoder = to_drm_encoder(nv_encoder);
+
+ nv_encoder->dcb = entry;
+ nv_encoder->or = ffs(entry->or) - 1;
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
+
+ drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type);
+ drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs);
+
+ encoder->possible_crtcs = entry->heads;
+ encoder->possible_clones = 0;
+
+ drm_mode_connector_attach_encoder(connector, encoder);
+ return 0;
+}
diff --git a/trunk/drivers/gpu/drm/nouveau/nvc0_fence.c b/trunk/drivers/gpu/drm/nouveau/nvc0_fence.c
index 2a56b1b551cb..53299eac9676 100644
--- a/trunk/drivers/gpu/drm/nouveau/nvc0_fence.c
+++ b/trunk/drivers/gpu/drm/nouveau/nvc0_fence.c
@@ -114,9 +114,17 @@ nvc0_fence_context_del(struct nouveau_channel *chan)
struct nvc0_fence_chan *fctx = chan->fence;
int i;
- for (i = 0; i < dev->mode_config.num_crtc; i++) {
- struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
- nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
+ if (nv_device(chan->drm->device)->card_type >= NV_D0) {
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ struct nouveau_bo *bo = nvd0_display_crtc_sema(dev, i);
+ nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
+ }
+ } else
+ if (nv_device(chan->drm->device)->card_type >= NV_50) {
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
+ nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
+ }
}
nouveau_bo_vma_del(priv->bo, &fctx->vma);
@@ -146,7 +154,12 @@ nvc0_fence_context_new(struct nouveau_channel *chan)
/* map display semaphore buffers into channel's vm */
for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) {
- struct nouveau_bo *bo = nv50_display_crtc_sema(chan->drm->dev, i);
+ struct nouveau_bo *bo;
+ if (nv_device(chan->drm->device)->card_type >= NV_D0)
+ bo = nvd0_display_crtc_sema(chan->drm->dev, i);
+ else
+ bo = nv50_display_crtc_sema(chan->drm->dev, i);
+
ret = nouveau_bo_vma_add(bo, client->vm, &fctx->dispc_vma[i]);
}
@@ -190,8 +203,6 @@ nvc0_fence_destroy(struct nouveau_drm *drm)
{
struct nvc0_fence_priv *priv = drm->fence;
nouveau_bo_unmap(priv->bo);
- if (priv->bo)
- nouveau_bo_unpin(priv->bo);
nouveau_bo_ref(NULL, &priv->bo);
drm->fence = NULL;
kfree(priv);
@@ -221,11 +232,8 @@ nvc0_fence_create(struct nouveau_drm *drm)
TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo);
if (ret == 0) {
ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
- if (ret == 0) {
+ if (ret == 0)
ret = nouveau_bo_map(priv->bo);
- if (ret)
- nouveau_bo_unpin(priv->bo);
- }
if (ret)
nouveau_bo_ref(NULL, &priv->bo);
}
diff --git a/trunk/drivers/gpu/drm/nouveau/nvd0_display.c b/trunk/drivers/gpu/drm/nouveau/nvd0_display.c
new file mode 100644
index 000000000000..c402fca2b2b8
--- /dev/null
+++ b/trunk/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -0,0 +1,2141 @@
+/*
+ * 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
+#include
+
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
+#include "nouveau_gem.h"
+#include "nouveau_connector.h"
+#include "nouveau_encoder.h"
+#include "nouveau_crtc.h"
+#include "nouveau_fence.h"
+#include "nv50_display.h"
+
+#include
+
+#include
+#include
+#include
+
+#define EVO_DMA_NR 9
+
+#define EVO_MASTER (0x00)
+#define EVO_FLIP(c) (0x01 + (c))
+#define EVO_OVLY(c) (0x05 + (c))
+#define EVO_OIMM(c) (0x09 + (c))
+#define EVO_CURS(c) (0x0d + (c))
+
+/* offsets in shared sync bo of various structures */
+#define EVO_SYNC(c, o) ((c) * 0x0100 + (o))
+#define EVO_MAST_NTFY EVO_SYNC( 0, 0x00)
+#define EVO_FLIP_SEM0(c) EVO_SYNC((c), 0x00)
+#define EVO_FLIP_SEM1(c) EVO_SYNC((c), 0x10)
+
+struct evo {
+ int idx;
+ dma_addr_t handle;
+ u32 *ptr;
+ struct {
+ u32 offset;
+ u16 value;
+ } sem;
+};
+
+struct nvd0_display {
+ struct nouveau_gpuobj *mem;
+ struct nouveau_bo *sync;
+ struct evo evo[9];
+
+ struct tasklet_struct tasklet;
+ u32 modeset;
+};
+
+static struct nvd0_display *
+nvd0_display(struct drm_device *dev)
+{
+ return nouveau_display(dev)->priv;
+}
+
+static struct drm_crtc *
+nvd0_display_crtc_get(struct drm_encoder *encoder)
+{
+ return nouveau_encoder(encoder)->crtc;
+}
+
+/******************************************************************************
+ * EVO channel helpers
+ *****************************************************************************/
+static inline int
+evo_icmd(struct drm_device *dev, int id, u32 mthd, u32 data)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ int ret = 0;
+ nv_mask(device, 0x610700 + (id * 0x10), 0x00000001, 0x00000001);
+ nv_wr32(device, 0x610704 + (id * 0x10), data);
+ nv_mask(device, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd);
+ if (!nv_wait(device, 0x610704 + (id * 0x10), 0x80000000, 0x00000000))
+ ret = -EBUSY;
+ nv_mask(device, 0x610700 + (id * 0x10), 0x00000001, 0x00000000);
+ return ret;
+}
+
+static u32 *
+evo_wait(struct drm_device *dev, int id, int nr)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nvd0_display *disp = nvd0_display(dev);
+ u32 put = nv_rd32(device, 0x640000 + (id * 0x1000)) / 4;
+
+ if (put + nr >= (PAGE_SIZE / 4)) {
+ disp->evo[id].ptr[put] = 0x20000000;
+
+ nv_wr32(device, 0x640000 + (id * 0x1000), 0x00000000);
+ if (!nv_wait(device, 0x640004 + (id * 0x1000), ~0, 0x00000000)) {
+ NV_ERROR(drm, "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 nouveau_device *device = nouveau_dev(dev);
+ struct nvd0_display *disp = nvd0_display(dev);
+
+ nv_wr32(device, 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 int
+evo_init_dma(struct drm_device *dev, int ch)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nvd0_display *disp = nvd0_display(dev);
+ u32 flags;
+
+ flags = 0x00000000;
+ if (ch == EVO_MASTER)
+ flags |= 0x01000000;
+
+ nv_wr32(device, 0x610494 + (ch * 0x0010), (disp->evo[ch].handle >> 8) | 3);
+ nv_wr32(device, 0x610498 + (ch * 0x0010), 0x00010000);
+ nv_wr32(device, 0x61049c + (ch * 0x0010), 0x00000001);
+ nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000010);
+ nv_wr32(device, 0x640000 + (ch * 0x1000), 0x00000000);
+ nv_wr32(device, 0x610490 + (ch * 0x0010), 0x00000013 | flags);
+ if (!nv_wait(device, 0x610490 + (ch * 0x0010), 0x80000000, 0x00000000)) {
+ NV_ERROR(drm, "PDISP: ch%d 0x%08x\n", ch,
+ nv_rd32(device, 0x610490 + (ch * 0x0010)));
+ return -EBUSY;
+ }
+
+ nv_mask(device, 0x610090, (1 << ch), (1 << ch));
+ nv_mask(device, 0x6100a0, (1 << ch), (1 << ch));
+ return 0;
+}
+
+static void
+evo_fini_dma(struct drm_device *dev, int ch)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+
+ if (!(nv_rd32(device, 0x610490 + (ch * 0x0010)) & 0x00000010))
+ return;
+
+ nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000000);
+ nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000003, 0x00000000);
+ nv_wait(device, 0x610490 + (ch * 0x0010), 0x80000000, 0x00000000);
+ nv_mask(device, 0x610090, (1 << ch), 0x00000000);
+ nv_mask(device, 0x6100a0, (1 << ch), 0x00000000);
+}
+
+static inline void
+evo_piow(struct drm_device *dev, int ch, u16 mthd, u32 data)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ nv_wr32(device, 0x640000 + (ch * 0x1000) + mthd, data);
+}
+
+static int
+evo_init_pio(struct drm_device *dev, int ch)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+
+ nv_wr32(device, 0x610490 + (ch * 0x0010), 0x00000001);
+ if (!nv_wait(device, 0x610490 + (ch * 0x0010), 0x00010000, 0x00010000)) {
+ NV_ERROR(drm, "PDISP: ch%d 0x%08x\n", ch,
+ nv_rd32(device, 0x610490 + (ch * 0x0010)));
+ return -EBUSY;
+ }
+
+ nv_mask(device, 0x610090, (1 << ch), (1 << ch));
+ nv_mask(device, 0x6100a0, (1 << ch), (1 << ch));
+ return 0;
+}
+
+static void
+evo_fini_pio(struct drm_device *dev, int ch)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+
+ if (!(nv_rd32(device, 0x610490 + (ch * 0x0010)) & 0x00000001))
+ return;
+
+ nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000010);
+ nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000001, 0x00000000);
+ nv_wait(device, 0x610490 + (ch * 0x0010), 0x00010000, 0x00000000);
+ nv_mask(device, 0x610090, (1 << ch), 0x00000000);
+ nv_mask(device, 0x6100a0, (1 << ch), 0x00000000);
+}
+
+static bool
+evo_sync_wait(void *data)
+{
+ return nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000;
+}
+
+static int
+evo_sync(struct drm_device *dev, int ch)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nvd0_display *disp = nvd0_display(dev);
+ u32 *push = evo_wait(dev, ch, 8);
+ if (push) {
+ nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000);
+ evo_mthd(push, 0x0084, 1);
+ evo_data(push, 0x80000000 | EVO_MAST_NTFY);
+ evo_mthd(push, 0x0080, 2);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00000000);
+ evo_kick(push, dev, ch);
+ if (nv_wait_cb(device, evo_sync_wait, disp->sync))
+ return 0;
+ }
+
+ return -EBUSY;
+}
+
+/******************************************************************************
+ * Page flipping channel
+ *****************************************************************************/
+struct nouveau_bo *
+nvd0_display_crtc_sema(struct drm_device *dev, int crtc)
+{
+ return nvd0_display(dev)->sync;
+}
+
+void
+nvd0_display_flip_stop(struct drm_crtc *crtc)
+{
+ struct nvd0_display *disp = nvd0_display(crtc->dev);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ struct evo *evo = &disp->evo[EVO_FLIP(nv_crtc->index)];
+ u32 *push;
+
+ push = evo_wait(crtc->dev, evo->idx, 8);
+ if (push) {
+ evo_mthd(push, 0x0084, 1);
+ evo_data(push, 0x00000000);
+ evo_mthd(push, 0x0094, 1);
+ evo_data(push, 0x00000000);
+ evo_mthd(push, 0x00c0, 1);
+ evo_data(push, 0x00000000);
+ evo_mthd(push, 0x0080, 1);
+ evo_data(push, 0x00000000);
+ evo_kick(push, crtc->dev, evo->idx);
+ }
+}
+
+int
+nvd0_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+ struct nouveau_channel *chan, u32 swap_interval)
+{
+ struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
+ struct nvd0_display *disp = nvd0_display(crtc->dev);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ struct evo *evo = &disp->evo[EVO_FLIP(nv_crtc->index)];
+ u64 offset;
+ u32 *push;
+ int ret;
+
+ swap_interval <<= 4;
+ if (swap_interval == 0)
+ swap_interval |= 0x100;
+
+ push = evo_wait(crtc->dev, evo->idx, 128);
+ if (unlikely(push == NULL))
+ return -EBUSY;
+
+ /* synchronise with the rendering channel, if necessary */
+ if (likely(chan)) {
+ ret = RING_SPACE(chan, 10);
+ if (ret)
+ return ret;
+
+
+ offset = nvc0_fence_crtc(chan, nv_crtc->index);
+ offset += evo->sem.offset;
+
+ BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+ OUT_RING (chan, upper_32_bits(offset));
+ OUT_RING (chan, lower_32_bits(offset));
+ OUT_RING (chan, 0xf00d0000 | evo->sem.value);
+ OUT_RING (chan, 0x1002);
+ BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+ OUT_RING (chan, upper_32_bits(offset));
+ OUT_RING (chan, lower_32_bits(offset ^ 0x10));
+ OUT_RING (chan, 0x74b1e000);
+ OUT_RING (chan, 0x1001);
+ FIRE_RING (chan);
+ } else {
+ nouveau_bo_wr32(disp->sync, evo->sem.offset / 4,
+ 0xf00d0000 | evo->sem.value);
+ evo_sync(crtc->dev, EVO_MASTER);
+ }
+
+ /* queue the flip */
+ evo_mthd(push, 0x0100, 1);
+ evo_data(push, 0xfffe0000);
+ evo_mthd(push, 0x0084, 1);
+ evo_data(push, swap_interval);
+ if (!(swap_interval & 0x00000100)) {
+ evo_mthd(push, 0x00e0, 1);
+ evo_data(push, 0x40000000);
+ }
+ evo_mthd(push, 0x0088, 4);
+ evo_data(push, evo->sem.offset);
+ evo_data(push, 0xf00d0000 | evo->sem.value);
+ evo_data(push, 0x74b1e000);
+ evo_data(push, NvEvoSync);
+ evo_mthd(push, 0x00a0, 2);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00000000);
+ evo_mthd(push, 0x00c0, 1);
+ evo_data(push, nv_fb->r_dma);
+ evo_mthd(push, 0x0110, 2);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00000000);
+ evo_mthd(push, 0x0400, 5);
+ evo_data(push, nv_fb->nvbo->bo.offset >> 8);
+ evo_data(push, 0);
+ evo_data(push, (fb->height << 16) | fb->width);
+ evo_data(push, nv_fb->r_pitch);
+ evo_data(push, nv_fb->r_format);
+ evo_mthd(push, 0x0080, 1);
+ evo_data(push, 0x00000000);
+ evo_kick(push, crtc->dev, evo->idx);
+
+ evo->sem.offset ^= 0x10;
+ evo->sem.value++;
+ return 0;
+}
+
+/******************************************************************************
+ * CRTC
+ *****************************************************************************/
+static int
+nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
+{
+ struct nouveau_drm *drm = nouveau_drm(nv_crtc->base.dev);
+ struct drm_device *dev = nv_crtc->base.dev;
+ struct nouveau_connector *nv_connector;
+ struct drm_connector *connector;
+ u32 *push, mode = 0x00;
+ u32 mthd;
+
+ nv_connector = nouveau_crtc_connector_get(nv_crtc);
+ connector = &nv_connector->base;
+ if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
+ if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
+ mode = DITHERING_MODE_DYNAMIC2X2;
+ } else {
+ mode = nv_connector->dithering_mode;
+ }
+
+ if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) {
+ if (connector->display_info.bpc >= 8)
+ mode |= DITHERING_DEPTH_8BPC;
+ } else {
+ mode |= nv_connector->dithering_depth;
+ }
+
+ if (nv_device(drm->device)->card_type < NV_E0)
+ mthd = 0x0490 + (nv_crtc->index * 0x0300);
+ else
+ mthd = 0x04a0 + (nv_crtc->index * 0x0300);
+
+ push = evo_wait(dev, EVO_MASTER, 4);
+ if (push) {
+ evo_mthd(push, mthd, 1);
+ evo_data(push, mode);
+ if (update) {
+ evo_mthd(push, 0x0080, 1);
+ evo_data(push, 0x00000000);
+ }
+ evo_kick(push, dev, EVO_MASTER);
+ }
+
+ return 0;
+}
+
+static int
+nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
+{
+ struct drm_display_mode *omode, *umode = &nv_crtc->base.mode;
+ struct drm_device *dev = nv_crtc->base.dev;
+ struct drm_crtc *crtc = &nv_crtc->base;
+ struct nouveau_connector *nv_connector;
+ int mode = DRM_MODE_SCALE_NONE;
+ u32 oX, oY, *push;
+
+ /* start off at the resolution we programmed the crtc for, this
+ * effectively handles NONE/FULL scaling
+ */
+ nv_connector = nouveau_crtc_connector_get(nv_crtc);
+ if (nv_connector && nv_connector->native_mode)
+ mode = nv_connector->scaling_mode;
+
+ if (mode != DRM_MODE_SCALE_NONE)
+ omode = nv_connector->native_mode;
+ else
+ omode = umode;
+
+ oX = omode->hdisplay;
+ oY = omode->vdisplay;
+ if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
+ oY *= 2;
+
+ /* add overscan compensation if necessary, will keep the aspect
+ * ratio the same as the backend mode unless overridden by the
+ * user setting both hborder and vborder properties.
+ */
+ if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
+ (nv_connector->underscan == UNDERSCAN_AUTO &&
+ nv_connector->edid &&
+ drm_detect_hdmi_monitor(nv_connector->edid)))) {
+ u32 bX = nv_connector->underscan_hborder;
+ u32 bY = nv_connector->underscan_vborder;
+ u32 aspect = (oY << 19) / oX;
+
+ if (bX) {
+ oX -= (bX * 2);
+ if (bY) oY -= (bY * 2);
+ else oY = ((oX * aspect) + (aspect / 2)) >> 19;
+ } else {
+ oX -= (oX >> 4) + 32;
+ if (bY) oY -= (bY * 2);
+ else oY = ((oX * aspect) + (aspect / 2)) >> 19;
+ }
+ }
+
+ /* handle CENTER/ASPECT scaling, taking into account the areas
+ * removed already for overscan compensation
+ */
+ switch (mode) {
+ case DRM_MODE_SCALE_CENTER:
+ oX = min((u32)umode->hdisplay, oX);
+ oY = min((u32)umode->vdisplay, oY);
+ /* fall-through */
+ case DRM_MODE_SCALE_ASPECT:
+ if (oY < oX) {
+ u32 aspect = (umode->hdisplay << 19) / umode->vdisplay;
+ oX = ((oY * aspect) + (aspect / 2)) >> 19;
+ } else {
+ u32 aspect = (umode->vdisplay << 19) / umode->hdisplay;
+ oY = ((oX * aspect) + (aspect / 2)) >> 19;
+ }
+ break;
+ default:
+ break;
+ }
+
+ push = evo_wait(dev, EVO_MASTER, 8);
+ if (push) {
+ evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
+ evo_data(push, (oY << 16) | oX);
+ evo_data(push, (oY << 16) | oX);
+ evo_data(push, (oY << 16) | oX);
+ 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, (umode->vdisplay << 16) | umode->hdisplay);
+ evo_kick(push, dev, EVO_MASTER);
+ if (update) {
+ nvd0_display_flip_stop(crtc);
+ nvd0_display_flip_next(crtc, crtc->fb, NULL, 1);
+ }
+ }
+
+ 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, EVO_MASTER, 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, EVO_MASTER);
+ }
+
+ 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, EVO_MASTER, 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, EVO_MASTER);
+ }
+}
+
+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;
+
+ nvd0_display_flip_stop(crtc);
+
+ push = evo_wait(crtc->dev, EVO_MASTER, 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, EVO_MASTER);
+ }
+
+ 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, EVO_MASTER, 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, EVO_MASTER);
+ }
+
+ nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true);
+ nvd0_display_flip_next(crtc, crtc->fb, NULL, 1);
+}
+
+static bool
+nvd0_crtc_mode_fixup(struct drm_crtc *crtc, const 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 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
+ u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
+ u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
+ u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
+ u32 vblan2e = 0, vblan2s = 1;
+ u32 *push;
+ int ret;
+
+ hactive = mode->htotal;
+ hsynce = mode->hsync_end - mode->hsync_start - 1;
+ hbackp = mode->htotal - mode->hsync_end;
+ hblanke = hsynce + hbackp;
+ hfrontp = mode->hsync_start - mode->hdisplay;
+ hblanks = mode->htotal - hfrontp - 1;
+
+ vactive = mode->vtotal * vscan / ilace;
+ vsynce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
+ vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
+ vblanke = vsynce + vbackp;
+ vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
+ vblanks = vactive - vfrontp - 1;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ vblan2e = vactive + vsynce + vbackp;
+ vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
+ vactive = (vactive * 2) + 1;
+ }
+
+ ret = nvd0_crtc_swap_fbs(crtc, old_fb);
+ if (ret)
+ return ret;
+
+ push = evo_wait(crtc->dev, EVO_MASTER, 64);
+ if (push) {
+ evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 6);
+ evo_data(push, 0x00000000);
+ evo_data(push, (vactive << 16) | hactive);
+ evo_data(push, ( vsynce << 16) | hsynce);
+ evo_data(push, (vblanke << 16) | hblanke);
+ evo_data(push, (vblanks << 16) | hblanks);
+ evo_data(push, (vblan2e << 16) | vblan2s);
+ 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, 0x04d0 + (nv_crtc->index * 0x300), 2);
+ evo_data(push, 0x00000311);
+ evo_data(push, 0x00000100);
+ evo_kick(push, crtc->dev, EVO_MASTER);
+ }
+
+ nv_connector = nouveau_crtc_connector_get(nv_crtc);
+ nvd0_crtc_set_dither(nv_crtc, false);
+ nvd0_crtc_set_scale(nv_crtc, 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_drm *drm = nouveau_drm(crtc->dev);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ int ret;
+
+ if (!crtc->fb) {
+ NV_DEBUG(drm, "No FB bound\n");
+ return 0;
+ }
+
+ ret = nvd0_crtc_swap_fbs(crtc, old_fb);
+ if (ret)
+ return ret;
+
+ nvd0_display_flip_stop(crtc);
+ nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
+ nvd0_display_flip_next(crtc, crtc->fb, NULL, 1);
+ 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_display_flip_stop(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);
+ int ch = EVO_CURS(nv_crtc->index);
+
+ evo_piow(crtc->dev, ch, 0x0084, (y << 16) | (x & 0xffff));
+ evo_piow(crtc->dev, ch, 0x0080, 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,
+ .page_flip = nouveau_crtc_page_flip,
+};
+
+static void
+nvd0_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
+{
+}
+
+static void
+nvd0_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
+{
+}
+
+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;
+ nv_crtc->cursor.set_offset = nvd0_cursor_set_offset;
+ nv_crtc->cursor.set_pos = nvd0_cursor_set_pos;
+ 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, NULL, &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, NULL, &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;
+ struct nouveau_device *device = nouveau_dev(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(device, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
+ nv_mask(device, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl);
+ nv_wait(device, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
+}
+
+static bool
+nvd0_dac_mode_fixup(struct drm_encoder *encoder,
+ const 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_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 syncs, magic, *push;
+
+ syncs = 0x00000001;
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ syncs |= 0x00000008;
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ syncs |= 0x00000010;
+
+ magic = 0x31ec6000 | (nv_crtc->index << 25);
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ magic |= 0x00000001;
+
+ nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON);
+
+ push = evo_wait(encoder->dev, EVO_MASTER, 8);
+ if (push) {
+ evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
+ evo_data(push, syncs);
+ evo_data(push, magic);
+ evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 2);
+ evo_data(push, 1 << nv_crtc->index);
+ evo_data(push, 0x00ff);
+ evo_kick(push, encoder->dev, EVO_MASTER);
+ }
+
+ 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, EVO_MASTER, 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, EVO_MASTER);
+ }
+
+ 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;
+ struct nouveau_device *device = nouveau_dev(dev);
+ int or = nv_encoder->or;
+ u32 load;
+
+ nv_wr32(device, 0x61a00c + (or * 0x800), 0x00100000);
+ udelay(9500);
+ nv_wr32(device, 0x61a00c + (or * 0x800), 0x80000000);
+
+ load = nv_rd32(device, 0x61a00c + (or * 0x800));
+ if ((load & 0x38000000) == 0x38000000)
+ status = connector_status_connected;
+
+ nv_wr32(device, 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_disconnect,
+ .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_output *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;
+}
+
+/******************************************************************************
+ * Audio
+ *****************************************************************************/
+static void
+nvd0_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_connector *nv_connector;
+ struct drm_device *dev = encoder->dev;
+ struct nouveau_device *device = nouveau_dev(dev);
+ int i, or = nv_encoder->or * 0x30;
+
+ nv_connector = nouveau_encoder_connector_get(nv_encoder);
+ if (!drm_detect_monitor_audio(nv_connector->edid))
+ return;
+
+ nv_mask(device, 0x10ec10 + or, 0x80000003, 0x80000001);
+
+ drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
+ if (nv_connector->base.eld[0]) {
+ u8 *eld = nv_connector->base.eld;
+
+ for (i = 0; i < eld[2] * 4; i++)
+ nv_wr32(device, 0x10ec00 + or, (i << 8) | eld[i]);
+ for (i = eld[2] * 4; i < 0x60; i++)
+ nv_wr32(device, 0x10ec00 + or, (i << 8) | 0x00);
+
+ nv_mask(device, 0x10ec10 + or, 0x80000002, 0x80000002);
+ }
+}
+
+static void
+nvd0_audio_disconnect(struct drm_encoder *encoder)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct drm_device *dev = encoder->dev;
+ struct nouveau_device *device = nouveau_dev(dev);
+ int or = nv_encoder->or * 0x30;
+
+ nv_mask(device, 0x10ec10 + or, 0x80000003, 0x80000000);
+}
+
+/******************************************************************************
+ * HDMI
+ *****************************************************************************/
+static void
+nvd0_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
+ struct nouveau_connector *nv_connector;
+ struct drm_device *dev = encoder->dev;
+ struct nouveau_device *device = nouveau_dev(dev);
+ int head = nv_crtc->index * 0x800;
+ u32 rekey = 56; /* binary driver, and tegra constant */
+ u32 max_ac_packet;
+
+ nv_connector = nouveau_encoder_connector_get(nv_encoder);
+ if (!drm_detect_hdmi_monitor(nv_connector->edid))
+ return;
+
+ max_ac_packet = mode->htotal - mode->hdisplay;
+ max_ac_packet -= rekey;
+ max_ac_packet -= 18; /* constant from tegra */
+ max_ac_packet /= 32;
+
+ /* AVI InfoFrame */
+ nv_mask(device, 0x616714 + head, 0x00000001, 0x00000000);
+ nv_wr32(device, 0x61671c + head, 0x000d0282);
+ nv_wr32(device, 0x616720 + head, 0x0000006f);
+ nv_wr32(device, 0x616724 + head, 0x00000000);
+ nv_wr32(device, 0x616728 + head, 0x00000000);
+ nv_wr32(device, 0x61672c + head, 0x00000000);
+ nv_mask(device, 0x616714 + head, 0x00000001, 0x00000001);
+
+ /* ??? InfoFrame? */
+ nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000000);
+ nv_wr32(device, 0x6167ac + head, 0x00000010);
+ nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000001);
+
+ /* HDMI_CTRL */
+ nv_mask(device, 0x616798 + head, 0x401f007f, 0x40000000 | rekey |
+ max_ac_packet << 16);
+
+ /* NFI, audio doesn't work without it though.. */
+ nv_mask(device, 0x616548 + head, 0x00000070, 0x00000000);
+
+ nvd0_audio_mode_set(encoder, mode);
+}
+
+static void
+nvd0_hdmi_disconnect(struct drm_encoder *encoder)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
+ struct drm_device *dev = encoder->dev;
+ struct nouveau_device *device = nouveau_dev(dev);
+ int head = nv_crtc->index * 0x800;
+
+ nvd0_audio_disconnect(encoder);
+
+ nv_mask(device, 0x616798 + head, 0x40000000, 0x00000000);
+ nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000000);
+ nv_mask(device, 0x616714 + head, 0x00000001, 0x00000000);
+}
+
+/******************************************************************************
+ * SOR
+ *****************************************************************************/
+static inline u32
+nvd0_sor_dp_lane_map(struct drm_device *dev, struct dcb_output *dcb, u8 lane)
+{
+ static const u8 nvd0[] = { 16, 8, 0, 24 };
+ return nvd0[lane];
+}
+
+static void
+nvd0_sor_dp_train_set(struct drm_device *dev, struct dcb_output *dcb, u8 pattern)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ const u32 loff = (or * 0x800) + (link * 0x80);
+ nv_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
+}
+
+static void
+nvd0_sor_dp_train_adj(struct drm_device *dev, struct dcb_output *dcb,
+ u8 lane, u8 swing, u8 preem)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ const u32 loff = (or * 0x800) + (link * 0x80);
+ u32 shift = nvd0_sor_dp_lane_map(dev, dcb, lane);
+ u32 mask = 0x000000ff << shift;
+ u8 *table, *entry, *config = NULL;
+
+ switch (swing) {
+ case 0: preem += 0; break;
+ case 1: preem += 4; break;
+ case 2: preem += 7; break;
+ case 3: preem += 9; break;
+ }
+
+ table = nouveau_dp_bios_data(dev, dcb, &entry);
+ if (table) {
+ if (table[0] == 0x30) {
+ config = entry + table[4];
+ config += table[5] * preem;
+ } else
+ if (table[0] == 0x40) {
+ config = table + table[1];
+ config += table[2] * table[3];
+ config += table[6] * preem;
+ }
+ }
+
+ if (!config) {
+ NV_ERROR(drm, "PDISP: unsupported DP table for chipset\n");
+ return;
+ }
+
+ nv_mask(device, 0x61c118 + loff, mask, config[1] << shift);
+ nv_mask(device, 0x61c120 + loff, mask, config[2] << shift);
+ nv_mask(device, 0x61c130 + loff, 0x0000ff00, config[3] << 8);
+ nv_mask(device, 0x61c13c + loff, 0x00000000, 0x00000000);
+}
+
+static void
+nvd0_sor_dp_link_set(struct drm_device *dev, struct dcb_output *dcb, int crtc,
+ int link_nr, u32 link_bw, bool enhframe)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ const u32 loff = (or * 0x800) + (link * 0x80);
+ const u32 soff = (or * 0x800);
+ u32 dpctrl = nv_rd32(device, 0x61c10c + loff) & ~0x001f4000;
+ u32 clksor = nv_rd32(device, 0x612300 + soff) & ~0x007c0000;
+ u32 script = 0x0000, lane_mask = 0;
+ u8 *table, *entry;
+ int i;
+
+ link_bw /= 27000;
+
+ table = nouveau_dp_bios_data(dev, dcb, &entry);
+ if (table) {
+ if (table[0] == 0x30) entry = ROMPTR(dev, entry[10]);
+ else if (table[0] == 0x40) entry = ROMPTR(dev, entry[9]);
+ else entry = NULL;
+
+ while (entry) {
+ if (entry[0] >= link_bw)
+ break;
+ entry += 3;
+ }
+
+ nouveau_bios_run_init_table(dev, script, dcb, crtc);
+ }
+
+ clksor |= link_bw << 18;
+ dpctrl |= ((1 << link_nr) - 1) << 16;
+ if (enhframe)
+ dpctrl |= 0x00004000;
+
+ for (i = 0; i < link_nr; i++)
+ lane_mask |= 1 << (nvd0_sor_dp_lane_map(dev, dcb, i) >> 3);
+
+ nv_wr32(device, 0x612300 + soff, clksor);
+ nv_wr32(device, 0x61c10c + loff, dpctrl);
+ nv_mask(device, 0x61c130 + loff, 0x0000000f, lane_mask);
+}
+
+static void
+nvd0_sor_dp_link_get(struct drm_device *dev, struct dcb_output *dcb,
+ u32 *link_nr, u32 *link_bw)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ const u32 loff = (or * 0x800) + (link * 0x80);
+ const u32 soff = (or * 0x800);
+ u32 dpctrl = nv_rd32(device, 0x61c10c + loff) & 0x000f0000;
+ u32 clksor = nv_rd32(device, 0x612300 + soff);
+
+ if (dpctrl > 0x00030000) *link_nr = 4;
+ else if (dpctrl > 0x00010000) *link_nr = 2;
+ else *link_nr = 1;
+
+ *link_bw = (clksor & 0x007c0000) >> 18;
+ *link_bw *= 27000;
+}
+
+static void
+nvd0_sor_dp_calc_tu(struct drm_device *dev, struct dcb_output *dcb,
+ u32 crtc, u32 datarate)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ const u32 symbol = 100000;
+ const u32 TU = 64;
+ u32 link_nr, link_bw;
+ u64 ratio, value;
+
+ nvd0_sor_dp_link_get(dev, dcb, &link_nr, &link_bw);
+
+ ratio = datarate;
+ ratio *= symbol;
+ do_div(ratio, link_nr * link_bw);
+
+ value = (symbol - ratio) * TU;
+ value *= ratio;
+ do_div(value, symbol);
+ do_div(value, symbol);
+
+ value += 5;
+ value |= 0x08000000;
+
+ nv_wr32(device, 0x616610 + (crtc * 0x800), value);
+}
+
+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 nouveau_device *device = nouveau_dev(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->dcb->or) {
+ if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
+ return;
+ break;
+ }
+ }
+
+ dpms_ctrl = (mode == DRM_MODE_DPMS_ON);
+ dpms_ctrl |= 0x80000000;
+
+ nv_wait(device, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
+ nv_mask(device, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
+ nv_wait(device, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
+ nv_wait(device, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
+
+ if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
+ struct dp_train_func func = {
+ .link_set = nvd0_sor_dp_link_set,
+ .train_set = nvd0_sor_dp_train_set,
+ .train_adj = nvd0_sor_dp_train_adj
+ };
+
+ nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, &func);
+ }
+}
+
+static bool
+nvd0_sor_mode_fixup(struct drm_encoder *encoder,
+ const 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_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, EVO_MASTER, 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, EVO_MASTER);
+ }
+
+ nvd0_hdmi_disconnect(encoder);
+
+ nv_encoder->crtc = NULL;
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
+ }
+}
+
+static void
+nvd0_sor_prepare(struct drm_encoder *encoder)
+{
+ nvd0_sor_disconnect(encoder);
+ if (nouveau_encoder(encoder)->dcb->type == DCB_OUTPUT_DP)
+ evo_sync(encoder->dev, EVO_MASTER);
+}
+
+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_device *dev = encoder->dev;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ 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 = &drm->vbios;
+ u32 mode_ctrl = (1 << nv_crtc->index);
+ u32 syncs, magic, *push;
+ u32 or_config;
+
+ syncs = 0x00000001;
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ syncs |= 0x00000008;
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ syncs |= 0x00000010;
+
+ magic = 0x31ec6000 | (nv_crtc->index << 25);
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ magic |= 0x00000001;
+
+ nv_connector = nouveau_encoder_connector_get(nv_encoder);
+ switch (nv_encoder->dcb->type) {
+ case DCB_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;
+
+ nvd0_hdmi_mode_set(encoder, mode);
+ break;
+ case DCB_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->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;
+ case DCB_OUTPUT_DP:
+ if (nv_connector->base.display_info.bpc == 6) {
+ nv_encoder->dp.datarate = mode->clock * 18 / 8;
+ syncs |= 0x00000002 << 6;
+ } else {
+ nv_encoder->dp.datarate = mode->clock * 24 / 8;
+ syncs |= 0x00000005 << 6;
+ }
+
+ if (nv_encoder->dcb->sorconf.link & 1)
+ mode_ctrl |= 0x00000800;
+ else
+ mode_ctrl |= 0x00000900;
+
+ or_config = (mode_ctrl & 0x00000f00) >> 8;
+ break;
+ default:
+ BUG_ON(1);
+ break;
+ }
+
+ nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
+
+ if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
+ nvd0_sor_dp_calc_tu(dev, nv_encoder->dcb, nv_crtc->index,
+ nv_encoder->dp.datarate);
+ }
+
+ push = evo_wait(dev, EVO_MASTER, 8);
+ if (push) {
+ evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
+ evo_data(push, syncs);
+ evo_data(push, magic);
+ evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 2);
+ evo_data(push, mode_ctrl);
+ evo_data(push, or_config);
+ evo_kick(push, dev, EVO_MASTER);
+ }
+
+ nv_encoder->crtc = encoder->crtc;
+}
+
+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_output *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_output *
+lookup_dcb(struct drm_device *dev, int id, u32 mc)
+{
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ int type, or, i, link = -1;
+
+ if (id < 4) {
+ type = DCB_OUTPUT_ANALOG;
+ or = id;
+ } else {
+ switch (mc & 0x00000f00) {
+ case 0x00000000: link = 0; type = DCB_OUTPUT_LVDS; break;
+ case 0x00000100: link = 0; type = DCB_OUTPUT_TMDS; break;
+ case 0x00000200: link = 1; type = DCB_OUTPUT_TMDS; break;
+ case 0x00000500: link = 0; type = DCB_OUTPUT_TMDS; break;
+ case 0x00000800: link = 0; type = DCB_OUTPUT_DP; break;
+ case 0x00000900: link = 1; type = DCB_OUTPUT_DP; break;
+ default:
+ NV_ERROR(drm, "PDISP: unknown SOR mc 0x%08x\n", mc);
+ return NULL;
+ }
+
+ or = id - 4;
+ }
+
+ for (i = 0; i < drm->vbios.dcb.entries; i++) {
+ struct dcb_output *dcb = &drm->vbios.dcb.entry[i];
+ if (dcb->type == type && (dcb->or & (1 << or)) &&
+ (link < 0 || link == !(dcb->sorconf.link & 1)))
+ return dcb;
+ }
+
+ NV_ERROR(drm, "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 nouveau_device *device = nouveau_dev(dev);
+ struct dcb_output *dcb;
+ int i;
+
+ for (i = 0; mask && i < 8; i++) {
+ u32 mcc = nv_rd32(device, 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(device, 0x6101d4, 0x00000000);
+ nv_wr32(device, 0x6109d4, 0x00000000);
+ nv_wr32(device, 0x6101d0, 0x80000000);
+}
+
+static void
+nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct dcb_output *dcb;
+ u32 or, tmp, pclk;
+ int i;
+
+ for (i = 0; mask && i < 8; i++) {
+ u32 mcc = nv_rd32(device, 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(device, 0x660450 + (crtc * 0x300)) / 1000;
+ NV_DEBUG(drm, "PDISP: crtc %d pclk %d mask 0x%08x\n",
+ crtc, pclk, mask);
+ if (pclk && (mask & 0x00010000)) {
+ nv50_crtc_set_clock(dev, crtc, pclk);
+ }
+
+ for (i = 0; mask && i < 8; i++) {
+ u32 mcp = nv_rd32(device, 0x660180 + (i * 0x20));
+ u32 cfg = nv_rd32(device, 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(device, 0x612200 + (crtc * 0x800), 0x00000000);
+ switch (dcb->type) {
+ case DCB_OUTPUT_ANALOG:
+ nv_wr32(device, 0x612280 + (or * 0x800), 0x00000000);
+ break;
+ case DCB_OUTPUT_TMDS:
+ case DCB_OUTPUT_LVDS:
+ case DCB_OUTPUT_DP:
+ if (cfg & 0x00000100)
+ tmp = 0x00000101;
+ else
+ tmp = 0x00000000;
+
+ nv_mask(device, 0x612300 + (or * 0x800), 0x00000707, tmp);
+ break;
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ nv_wr32(device, 0x6101d4, 0x00000000);
+ nv_wr32(device, 0x6109d4, 0x00000000);
+ nv_wr32(device, 0x6101d0, 0x80000000);
+}
+
+static void
+nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct dcb_output *dcb;
+ int pclk, i;
+
+ pclk = nv_rd32(device, 0x660450 + (crtc * 0x300)) / 1000;
+
+ for (i = 0; mask && i < 8; i++) {
+ u32 mcp = nv_rd32(device, 0x660180 + (i * 0x20));
+ u32 cfg = nv_rd32(device, 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(device, 0x6101d4, 0x00000000);
+ nv_wr32(device, 0x6109d4, 0x00000000);
+ nv_wr32(device, 0x6101d0, 0x80000000);
+}
+
+static void
+nvd0_display_bh(unsigned long data)
+{
+ struct drm_device *dev = (struct drm_device *)data;
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nvd0_display *disp = nvd0_display(dev);
+ u32 mask = 0, crtc = ~0;
+ int i;
+
+ if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
+ NV_INFO(drm, "PDISP: modeset req %d\n", disp->modeset);
+ NV_INFO(drm, " STAT: 0x%08x 0x%08x 0x%08x\n",
+ nv_rd32(device, 0x6101d0),
+ nv_rd32(device, 0x6101d4), nv_rd32(device, 0x6109d4));
+ for (i = 0; i < 8; i++) {
+ NV_INFO(drm, " %s%d: 0x%08x 0x%08x\n",
+ i < 4 ? "DAC" : "SOR", i,
+ nv_rd32(device, 0x640180 + (i * 0x20)),
+ nv_rd32(device, 0x660180 + (i * 0x20)));
+ }
+ }
+
+ while (!mask && ++crtc < dev->mode_config.num_crtc)
+ mask = nv_rd32(device, 0x6101d4 + (crtc * 0x800));
+
+ 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);
+}
+
+void
+nvd0_display_intr(struct drm_device *dev)
+{
+ struct nvd0_display *disp = nvd0_display(dev);
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ u32 intr = nv_rd32(device, 0x610088);
+
+ if (intr & 0x00000001) {
+ u32 stat = nv_rd32(device, 0x61008c);
+ nv_wr32(device, 0x61008c, stat);
+ intr &= ~0x00000001;
+ }
+
+ if (intr & 0x00000002) {
+ u32 stat = nv_rd32(device, 0x61009c);
+ int chid = ffs(stat) - 1;
+ if (chid >= 0) {
+ u32 mthd = nv_rd32(device, 0x6101f0 + (chid * 12));
+ u32 data = nv_rd32(device, 0x6101f4 + (chid * 12));
+ u32 unkn = nv_rd32(device, 0x6101f8 + (chid * 12));
+
+ NV_INFO(drm, "EvoCh: chid %d mthd 0x%04x data 0x%08x "
+ "0x%08x 0x%08x\n",
+ chid, (mthd & 0x0000ffc), data, mthd, unkn);
+ nv_wr32(device, 0x61009c, (1 << chid));
+ nv_wr32(device, 0x6101f0 + (chid * 12), 0x90000000);
+ }
+
+ intr &= ~0x00000002;
+ }
+
+ if (intr & 0x00100000) {
+ u32 stat = nv_rd32(device, 0x6100ac);
+
+ if (stat & 0x00000007) {
+ disp->modeset = stat;
+ tasklet_schedule(&disp->tasklet);
+
+ nv_wr32(device, 0x6100ac, (stat & 0x00000007));
+ stat &= ~0x00000007;
+ }
+
+ if (stat) {
+ NV_INFO(drm, "PDISP: unknown intr24 0x%08x\n", stat);
+ nv_wr32(device, 0x6100ac, stat);
+ }
+
+ intr &= ~0x00100000;
+ }
+
+ intr &= ~0x0f000000; /* vblank, handled in core */
+ if (intr)
+ NV_INFO(drm, "PDISP: unknown intr 0x%08x\n", intr);
+}
+
+/******************************************************************************
+ * Init
+ *****************************************************************************/
+void
+nvd0_display_fini(struct drm_device *dev)
+{
+ int i;
+
+ /* fini cursors + overlays + flips */
+ for (i = 1; i >= 0; i--) {
+ evo_fini_pio(dev, EVO_CURS(i));
+ evo_fini_pio(dev, EVO_OIMM(i));
+ evo_fini_dma(dev, EVO_OVLY(i));
+ evo_fini_dma(dev, EVO_FLIP(i));
+ }
+
+ /* fini master */
+ evo_fini_dma(dev, EVO_MASTER);
+}
+
+int
+nvd0_display_init(struct drm_device *dev)
+{
+ struct nvd0_display *disp = nvd0_display(dev);
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ int ret, i;
+ u32 *push;
+
+ if (nv_rd32(device, 0x6100ac) & 0x00000100) {
+ nv_wr32(device, 0x6100ac, 0x00000100);
+ nv_mask(device, 0x6194e8, 0x00000001, 0x00000000);
+ if (!nv_wait(device, 0x6194e8, 0x00000002, 0x00000000)) {
+ NV_ERROR(drm, "PDISP: 0x6194e8 0x%08x\n",
+ nv_rd32(device, 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(device, 0x61a000 + (i * 0x800));
+ nv_wr32(device, 0x6101c0 + (i * 0x800), dac);
+ }
+
+ for (i = 0; i < 4; i++) {
+ u32 sor = nv_rd32(device, 0x61c000 + (i * 0x800));
+ nv_wr32(device, 0x6301c4 + (i * 0x800), sor);
+ }
+
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ u32 crtc0 = nv_rd32(device, 0x616104 + (i * 0x800));
+ u32 crtc1 = nv_rd32(device, 0x616108 + (i * 0x800));
+ u32 crtc2 = nv_rd32(device, 0x61610c + (i * 0x800));
+ nv_wr32(device, 0x6101b4 + (i * 0x800), crtc0);
+ nv_wr32(device, 0x6101b8 + (i * 0x800), crtc1);
+ nv_wr32(device, 0x6101bc + (i * 0x800), crtc2);
+ }
+
+ /* point at our hash table / objects, enable interrupts */
+ nv_wr32(device, 0x610010, (disp->mem->addr >> 8) | 9);
+ nv_mask(device, 0x6100b0, 0x00000307, 0x00000307);
+
+ /* init master */
+ ret = evo_init_dma(dev, EVO_MASTER);
+ if (ret)
+ goto error;
+
+ /* init flips + overlays + cursors */
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ if ((ret = evo_init_dma(dev, EVO_FLIP(i))) ||
+ (ret = evo_init_dma(dev, EVO_OVLY(i))) ||
+ (ret = evo_init_pio(dev, EVO_OIMM(i))) ||
+ (ret = evo_init_pio(dev, EVO_CURS(i))))
+ goto error;
+ }
+
+ push = evo_wait(dev, EVO_MASTER, 32);
+ if (!push) {
+ ret = -EBUSY;
+ goto error;
+ }
+ 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, EVO_MASTER);
+
+error:
+ if (ret)
+ nvd0_display_fini(dev);
+ return ret;
+}
+
+void
+nvd0_display_destroy(struct drm_device *dev)
+{
+ struct nvd0_display *disp = nvd0_display(dev);
+ struct pci_dev *pdev = dev->pdev;
+ int i;
+
+ for (i = 0; i < EVO_DMA_NR; i++) {
+ struct evo *evo = &disp->evo[i];
+ pci_free_consistent(pdev, PAGE_SIZE, evo->ptr, evo->handle);
+ }
+
+ nouveau_gpuobj_ref(NULL, &disp->mem);
+ nouveau_bo_unmap(disp->sync);
+ nouveau_bo_ref(NULL, &disp->sync);
+
+ nouveau_display(dev)->priv = NULL;
+ kfree(disp);
+}
+
+int
+nvd0_display_create(struct drm_device *dev)
+{
+ struct nouveau_device *device = nouveau_dev(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_bar *bar = nouveau_bar(device);
+ struct nouveau_fb *pfb = nouveau_fb(device);
+ struct dcb_table *dcb = &drm->vbios.dcb;
+ struct drm_connector *connector, *tmp;
+ struct pci_dev *pdev = dev->pdev;
+ struct nvd0_display *disp;
+ struct dcb_output *dcbe;
+ int crtcs, ret, i;
+
+ disp = kzalloc(sizeof(*disp), GFP_KERNEL);
+ if (!disp)
+ return -ENOMEM;
+
+ nouveau_display(dev)->priv = disp;
+ nouveau_display(dev)->dtor = nvd0_display_destroy;
+ nouveau_display(dev)->init = nvd0_display_init;
+ nouveau_display(dev)->fini = nvd0_display_fini;
+
+ /* create crtc objects to represent the hw heads */
+ crtcs = nv_rd32(device, 0x022448);
+ for (i = 0; i < crtcs; 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(drm, "skipping off-chip encoder %d/%d\n",
+ dcbe->type, ffs(dcbe->or) - 1);
+ continue;
+ }
+
+ switch (dcbe->type) {
+ case DCB_OUTPUT_TMDS:
+ case DCB_OUTPUT_LVDS:
+ case DCB_OUTPUT_DP:
+ nvd0_sor_create(connector, dcbe);
+ break;
+ case DCB_OUTPUT_ANALOG:
+ nvd0_dac_create(connector, dcbe);
+ break;
+ default:
+ NV_WARN(drm, "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(drm, "%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);
+
+ /* small shared memory area we use for notifiers and semaphores */
+ ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
+ 0, 0x0000, NULL, &disp->sync);
+ if (!ret) {
+ ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM);
+ if (!ret)
+ ret = nouveau_bo_map(disp->sync);
+ if (ret)
+ nouveau_bo_ref(NULL, &disp->sync);
+ }
+
+ if (ret)
+ goto out;
+
+ /* hash table and dma objects for the memory areas we care about */
+ ret = nouveau_gpuobj_new(nv_object(device), NULL, 0x4000, 0x10000,
+ NVOBJ_FLAG_ZERO_ALLOC, &disp->mem);
+ if (ret)
+ goto out;
+
+ /* create evo dma channels */
+ for (i = 0; i < EVO_DMA_NR; i++) {
+ struct evo *evo = &disp->evo[i];
+ u64 offset = disp->sync->bo.offset;
+ u32 dmao = 0x1000 + (i * 0x100);
+ u32 hash = 0x0000 + (i * 0x040);
+
+ evo->idx = i;
+ evo->sem.offset = EVO_SYNC(evo->idx, 0x00);
+ evo->ptr = pci_alloc_consistent(pdev, PAGE_SIZE, &evo->handle);
+ if (!evo->ptr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ nv_wo32(disp->mem, dmao + 0x00, 0x00000049);
+ nv_wo32(disp->mem, dmao + 0x04, (offset + 0x0000) >> 8);
+ nv_wo32(disp->mem, dmao + 0x08, (offset + 0x0fff) >> 8);
+ nv_wo32(disp->mem, dmao + 0x0c, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x10, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x14, 0x00000000);
+ nv_wo32(disp->mem, hash + 0x00, NvEvoSync);
+ nv_wo32(disp->mem, hash + 0x04, 0x00000001 | (i << 27) |
+ ((dmao + 0x00) << 9));
+
+ nv_wo32(disp->mem, dmao + 0x20, 0x00000049);
+ nv_wo32(disp->mem, dmao + 0x24, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x28, (pfb->ram.size - 1) >> 8);
+ nv_wo32(disp->mem, dmao + 0x2c, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x30, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x34, 0x00000000);
+ nv_wo32(disp->mem, hash + 0x08, NvEvoVRAM);
+ nv_wo32(disp->mem, hash + 0x0c, 0x00000001 | (i << 27) |
+ ((dmao + 0x20) << 9));
+
+ nv_wo32(disp->mem, dmao + 0x40, 0x00000009);
+ nv_wo32(disp->mem, dmao + 0x44, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x48, (pfb->ram.size - 1) >> 8);
+ nv_wo32(disp->mem, dmao + 0x4c, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x50, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x54, 0x00000000);
+ nv_wo32(disp->mem, hash + 0x10, NvEvoVRAM_LP);
+ nv_wo32(disp->mem, hash + 0x14, 0x00000001 | (i << 27) |
+ ((dmao + 0x40) << 9));
+
+ nv_wo32(disp->mem, dmao + 0x60, 0x0fe00009);
+ nv_wo32(disp->mem, dmao + 0x64, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x68, (pfb->ram.size - 1) >> 8);
+ nv_wo32(disp->mem, dmao + 0x6c, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x70, 0x00000000);
+ nv_wo32(disp->mem, dmao + 0x74, 0x00000000);
+ nv_wo32(disp->mem, hash + 0x18, NvEvoFB32);
+ nv_wo32(disp->mem, hash + 0x1c, 0x00000001 | (i << 27) |
+ ((dmao + 0x60) << 9));
+ }
+
+ bar->flush(bar);
+
+out:
+ if (ret)
+ nvd0_display_destroy(dev);
+ return ret;
+}
diff --git a/trunk/drivers/gpu/drm/tegra/dc.c b/trunk/drivers/gpu/drm/tegra/dc.c
index 074410371e2a..53b98520ebd6 100644
--- a/trunk/drivers/gpu/drm/tegra/dc.c
+++ b/trunk/drivers/gpu/drm/tegra/dc.c
@@ -218,7 +218,7 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
}
bpp = crtc->fb->bits_per_pixel / 8;
- win.stride = crtc->fb->pitches[0];
+ win.stride = win.outw * bpp;
/* program window registers */
value = tegra_dc_readl(dc, DC_CMD_DISPLAY_WINDOW_HEADER);
@@ -818,7 +818,6 @@ static int tegra_dc_remove(struct platform_device *pdev)
}
static struct of_device_id tegra_dc_of_match[] = {
- { .compatible = "nvidia,tegra30-dc", },
{ .compatible = "nvidia,tegra20-dc", },
{ },
};
diff --git a/trunk/drivers/gpu/drm/tegra/hdmi.c b/trunk/drivers/gpu/drm/tegra/hdmi.c
index ab4016412bbf..58f55dc6d59d 100644
--- a/trunk/drivers/gpu/drm/tegra/hdmi.c
+++ b/trunk/drivers/gpu/drm/tegra/hdmi.c
@@ -1318,8 +1318,8 @@ static int tegra_hdmi_remove(struct platform_device *pdev)
}
static struct of_device_id tegra_hdmi_of_match[] = {
- { .compatible = "nvidia,tegra30-hdmi", },
{ .compatible = "nvidia,tegra20-hdmi", },
+ { .compatible = "nvidia,tegra30-hdmi", },
{ },
};
diff --git a/trunk/drivers/gpu/drm/tegra/host1x.c b/trunk/drivers/gpu/drm/tegra/host1x.c
index bdb97a564d82..1f728cd7f61a 100644
--- a/trunk/drivers/gpu/drm/tegra/host1x.c
+++ b/trunk/drivers/gpu/drm/tegra/host1x.c
@@ -68,8 +68,6 @@ static int host1x_parse_dt(struct host1x *host1x)
static const char * const compat[] = {
"nvidia,tegra20-dc",
"nvidia,tegra20-hdmi",
- "nvidia,tegra30-dc",
- "nvidia,tegra30-hdmi",
};
unsigned int i;
int err;
@@ -270,7 +268,6 @@ int host1x_unregister_client(struct host1x *host1x,
}
static struct of_device_id tegra_host1x_of_match[] = {
- { .compatible = "nvidia,tegra30-host1x", },
{ .compatible = "nvidia,tegra20-host1x", },
{ },
};
diff --git a/trunk/drivers/gpu/drm/ttm/ttm_bo.c b/trunk/drivers/gpu/drm/ttm/ttm_bo.c
index 2c54c3d414b3..7426fe59108e 100644
--- a/trunk/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/trunk/drivers/gpu/drm/ttm/ttm_bo.c
@@ -696,7 +696,6 @@ static void ttm_bo_release(struct kref *kref)
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
- write_lock(&bdev->vm_lock);
if (likely(bo->vm_node != NULL)) {
rb_erase(&bo->vm_rb, &bdev->addr_space_rb);
drm_mm_put_block(bo->vm_node);
@@ -708,14 +707,18 @@ static void ttm_bo_release(struct kref *kref)
ttm_mem_io_unlock(man);
ttm_bo_cleanup_refs_or_queue(bo);
kref_put(&bo->list_kref, ttm_bo_release_list);
+ write_lock(&bdev->vm_lock);
}
void ttm_bo_unref(struct ttm_buffer_object **p_bo)
{
struct ttm_buffer_object *bo = *p_bo;
+ struct ttm_bo_device *bdev = bo->bdev;
*p_bo = NULL;
+ write_lock(&bdev->vm_lock);
kref_put(&bo->kref, ttm_bo_release);
+ write_unlock(&bdev->vm_lock);
}
EXPORT_SYMBOL(ttm_bo_unref);
diff --git a/trunk/drivers/gpu/drm/ttm/ttm_bo_vm.c b/trunk/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 74705f329d99..3ba72dbdc4bd 100644
--- a/trunk/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/trunk/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -259,8 +259,8 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
read_lock(&bdev->vm_lock);
bo = ttm_bo_vm_lookup_rb(bdev, vma->vm_pgoff,
(vma->vm_end - vma->vm_start) >> PAGE_SHIFT);
- if (likely(bo != NULL) && !kref_get_unless_zero(&bo->kref))
- bo = NULL;
+ if (likely(bo != NULL))
+ ttm_bo_reference(bo);
read_unlock(&bdev->vm_lock);
if (unlikely(bo == NULL)) {
diff --git a/trunk/drivers/gpu/drm/ttm/ttm_object.c b/trunk/drivers/gpu/drm/ttm/ttm_object.c
index 58a5f3261c0b..f18eeb458139 100644
--- a/trunk/drivers/gpu/drm/ttm/ttm_object.c
+++ b/trunk/drivers/gpu/drm/ttm/ttm_object.c
@@ -157,11 +157,11 @@ int ttm_base_object_init(struct ttm_object_file *tfile,
base->refcount_release = refcount_release;
base->ref_obj_release = ref_obj_release;
base->object_type = object_type;
- kref_init(&base->refcount);
spin_lock(&tdev->object_lock);
- ret = drm_ht_just_insert_please_rcu(&tdev->object_hash,
- &base->hash,
- (unsigned long)base, 31, 0, 0);
+ kref_init(&base->refcount);
+ ret = drm_ht_just_insert_please(&tdev->object_hash,
+ &base->hash,
+ (unsigned long)base, 31, 0, 0);
spin_unlock(&tdev->object_lock);
if (unlikely(ret != 0))
goto out_err0;
@@ -174,9 +174,7 @@ int ttm_base_object_init(struct ttm_object_file *tfile,
return 0;
out_err1:
- spin_lock(&tdev->object_lock);
- (void)drm_ht_remove_item_rcu(&tdev->object_hash, &base->hash);
- spin_unlock(&tdev->object_lock);
+ (void)drm_ht_remove_item(&tdev->object_hash, &base->hash);
out_err0:
return ret;
}
@@ -189,15 +187,8 @@ static void ttm_release_base(struct kref *kref)
struct ttm_object_device *tdev = base->tfile->tdev;
spin_lock(&tdev->object_lock);
- (void)drm_ht_remove_item_rcu(&tdev->object_hash, &base->hash);
+ (void)drm_ht_remove_item(&tdev->object_hash, &base->hash);
spin_unlock(&tdev->object_lock);
-
- /*
- * Note: We don't use synchronize_rcu() here because it's far
- * too slow. It's up to the user to free the object using
- * call_rcu() or ttm_base_object_kfree().
- */
-
if (base->refcount_release) {
ttm_object_file_unref(&base->tfile);
base->refcount_release(&base);
@@ -223,7 +214,7 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
int ret;
rcu_read_lock();
- ret = drm_ht_find_item_rcu(&tdev->object_hash, key, &hash);
+ ret = drm_ht_find_item(&tdev->object_hash, key, &hash);
if (likely(ret == 0)) {
base = drm_hash_entry(hash, struct ttm_base_object, hash);
diff --git a/trunk/drivers/gpu/drm/vmwgfx/Makefile b/trunk/drivers/gpu/drm/vmwgfx/Makefile
index 2cc6cd91ac11..586869c8c11f 100644
--- a/trunk/drivers/gpu/drm/vmwgfx/Makefile
+++ b/trunk/drivers/gpu/drm/vmwgfx/Makefile
@@ -5,7 +5,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \
vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \
- vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \
- vmwgfx_surface.o
+ vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o
obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
diff --git a/trunk/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h b/trunk/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h
deleted file mode 100644
index 8369c3ba10fe..000000000000
--- a/trunk/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h
+++ /dev/null
@@ -1,909 +0,0 @@
-/**************************************************************************
- *
- * Copyright © 2008-2012 VMware, Inc., Palo Alto, CA., USA
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-#ifdef __KERNEL__
-
-#include
-#define surf_size_struct struct drm_vmw_size
-
-#else /* __KERNEL__ */
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(_A) (sizeof(_A) / sizeof((_A)[0]))
-#endif /* ARRAY_SIZE */
-
-#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
-#define max_t(type, x, y) ((x) > (y) ? (x) : (y))
-#define surf_size_struct SVGA3dSize
-#define u32 uint32
-
-#endif /* __KERNEL__ */
-
-#include "svga3d_reg.h"
-
-/*
- * enum svga3d_block_desc describes the active data channels in a block.
- *
- * There can be at-most four active channels in a block:
- * 1. Red, bump W, luminance and depth are stored in the first channel.
- * 2. Green, bump V and stencil are stored in the second channel.
- * 3. Blue and bump U are stored in the third channel.
- * 4. Alpha and bump Q are stored in the fourth channel.
- *
- * Block channels can be used to store compressed and buffer data:
- * 1. For compressed formats, only the data channel is used and its size
- * is equal to that of a singular block in the compression scheme.
- * 2. For buffer formats, only the data channel is used and its size is
- * exactly one byte in length.
- * 3. In each case the bit depth represent the size of a singular block.
- *
- * Note: Compressed and IEEE formats do not use the bitMask structure.
- */
-
-enum svga3d_block_desc {
- SVGA3DBLOCKDESC_NONE = 0, /* No channels are active */
- SVGA3DBLOCKDESC_BLUE = 1 << 0, /* Block with red channel
- data */
- SVGA3DBLOCKDESC_U = 1 << 0, /* Block with bump U channel
- data */
- SVGA3DBLOCKDESC_UV_VIDEO = 1 << 7, /* Block with alternating video
- U and V */
- SVGA3DBLOCKDESC_GREEN = 1 << 1, /* Block with green channel
- data */
- SVGA3DBLOCKDESC_V = 1 << 1, /* Block with bump V channel
- data */
- SVGA3DBLOCKDESC_STENCIL = 1 << 1, /* Block with a stencil
- channel */
- SVGA3DBLOCKDESC_RED = 1 << 2, /* Block with blue channel
- data */
- SVGA3DBLOCKDESC_W = 1 << 2, /* Block with bump W channel
- data */
- SVGA3DBLOCKDESC_LUMINANCE = 1 << 2, /* Block with luminance channel
- data */
- SVGA3DBLOCKDESC_Y = 1 << 2, /* Block with video luminance
- data */
- SVGA3DBLOCKDESC_DEPTH = 1 << 2, /* Block with depth channel */
- SVGA3DBLOCKDESC_ALPHA = 1 << 3, /* Block with an alpha
- channel */
- SVGA3DBLOCKDESC_Q = 1 << 3, /* Block with bump Q channel
- data */
- SVGA3DBLOCKDESC_BUFFER = 1 << 4, /* Block stores 1 byte of
- data */
- SVGA3DBLOCKDESC_COMPRESSED = 1 << 5, /* Block stores n bytes of
- data depending on the
- compression method used */
- SVGA3DBLOCKDESC_IEEE_FP = 1 << 6, /* Block stores data in an IEEE
- floating point
- representation in
- all channels */
- SVGA3DBLOCKDESC_PLANAR_YUV = 1 << 8, /* Three separate blocks store
- data. */
- SVGA3DBLOCKDESC_U_VIDEO = 1 << 9, /* Block with U video data */
- SVGA3DBLOCKDESC_V_VIDEO = 1 << 10, /* Block with V video data */
- SVGA3DBLOCKDESC_EXP = 1 << 11, /* Shared exponent */
- SVGA3DBLOCKDESC_SRGB = 1 << 12, /* Data is in sRGB format */
- SVGA3DBLOCKDESC_2PLANAR_YUV = 1 << 13, /* 2 planes of Y, UV,
- e.g., NV12. */
- SVGA3DBLOCKDESC_3PLANAR_YUV = 1 << 14, /* 3 planes of separate
- Y, U, V, e.g., YV12. */
-
- SVGA3DBLOCKDESC_RG = SVGA3DBLOCKDESC_RED |
- SVGA3DBLOCKDESC_GREEN,
- SVGA3DBLOCKDESC_RGB = SVGA3DBLOCKDESC_RG |
- SVGA3DBLOCKDESC_BLUE,
- SVGA3DBLOCKDESC_RGB_SRGB = SVGA3DBLOCKDESC_RGB |
- SVGA3DBLOCKDESC_SRGB,
- SVGA3DBLOCKDESC_RGBA = SVGA3DBLOCKDESC_RGB |
- SVGA3DBLOCKDESC_ALPHA,
- SVGA3DBLOCKDESC_RGBA_SRGB = SVGA3DBLOCKDESC_RGBA |
- SVGA3DBLOCKDESC_SRGB,
- SVGA3DBLOCKDESC_UV = SVGA3DBLOCKDESC_U |
- SVGA3DBLOCKDESC_V,
- SVGA3DBLOCKDESC_UVL = SVGA3DBLOCKDESC_UV |
- SVGA3DBLOCKDESC_LUMINANCE,
- SVGA3DBLOCKDESC_UVW = SVGA3DBLOCKDESC_UV |
- SVGA3DBLOCKDESC_W,
- SVGA3DBLOCKDESC_UVWA = SVGA3DBLOCKDESC_UVW |
- SVGA3DBLOCKDESC_ALPHA,
- SVGA3DBLOCKDESC_UVWQ = SVGA3DBLOCKDESC_U |
- SVGA3DBLOCKDESC_V |
- SVGA3DBLOCKDESC_W |
- SVGA3DBLOCKDESC_Q,
- SVGA3DBLOCKDESC_LA = SVGA3DBLOCKDESC_LUMINANCE |
- SVGA3DBLOCKDESC_ALPHA,
- SVGA3DBLOCKDESC_R_FP = SVGA3DBLOCKDESC_RED |
- SVGA3DBLOCKDESC_IEEE_FP,
- SVGA3DBLOCKDESC_RG_FP = SVGA3DBLOCKDESC_R_FP |
- SVGA3DBLOCKDESC_GREEN,
- SVGA3DBLOCKDESC_RGB_FP = SVGA3DBLOCKDESC_RG_FP |
- SVGA3DBLOCKDESC_BLUE,
- SVGA3DBLOCKDESC_RGBA_FP = SVGA3DBLOCKDESC_RGB_FP |
- SVGA3DBLOCKDESC_ALPHA,
- SVGA3DBLOCKDESC_DS = SVGA3DBLOCKDESC_DEPTH |
- SVGA3DBLOCKDESC_STENCIL,
- SVGA3DBLOCKDESC_YUV = SVGA3DBLOCKDESC_UV_VIDEO |
- SVGA3DBLOCKDESC_Y,
- SVGA3DBLOCKDESC_AYUV = SVGA3DBLOCKDESC_ALPHA |
- SVGA3DBLOCKDESC_Y |
- SVGA3DBLOCKDESC_U_VIDEO |
- SVGA3DBLOCKDESC_V_VIDEO,
- SVGA3DBLOCKDESC_RGBE = SVGA3DBLOCKDESC_RGB |
- SVGA3DBLOCKDESC_EXP,
- SVGA3DBLOCKDESC_COMPRESSED_SRGB = SVGA3DBLOCKDESC_COMPRESSED |
- SVGA3DBLOCKDESC_SRGB,
- SVGA3DBLOCKDESC_NV12 = SVGA3DBLOCKDESC_PLANAR_YUV |
- SVGA3DBLOCKDESC_2PLANAR_YUV,
- SVGA3DBLOCKDESC_YV12 = SVGA3DBLOCKDESC_PLANAR_YUV |
- SVGA3DBLOCKDESC_3PLANAR_YUV,
-};
-
-/*
- * SVGA3dSurfaceDesc describes the actual pixel data.
- *
- * This structure provides the following information:
- * 1. Block description.
- * 2. Dimensions of a block in the surface.
- * 3. Size of block in bytes.
- * 4. Bit depth of the pixel data.
- * 5. Channel bit depths and masks (if applicable).
- */
-#define SVGA3D_CHANNEL_DEF(type) \
- struct { \
- union { \
- type blue; \
- type u; \
- type uv_video; \
- type u_video; \
- }; \
- union { \
- type green; \
- type v; \
- type stencil; \
- type v_video; \
- }; \
- union { \
- type red; \
- type w; \
- type luminance; \
- type y; \
- type depth; \
- type data; \
- }; \
- union { \
- type alpha; \
- type q; \
- type exp; \
- }; \
- }
-
-struct svga3d_surface_desc {
- enum svga3d_block_desc block_desc;
- surf_size_struct block_size;
- u32 bytes_per_block;
- u32 pitch_bytes_per_block;
-
- struct {
- u32 total;
- SVGA3D_CHANNEL_DEF(uint8);
- } bit_depth;
-
- struct {
- SVGA3D_CHANNEL_DEF(uint8);
- } bit_offset;
-};
-
-static const struct svga3d_surface_desc svga3d_surface_descs[] = {
- {SVGA3DBLOCKDESC_NONE,
- {1, 1, 1}, 0, 0, {0, {{0}, {0}, {0}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_FORMAT_INVALID */
-
- {SVGA3DBLOCKDESC_RGB,
- {1, 1, 1}, 4, 4, {24, {{8}, {8}, {8}, {0} } },
- {{{0}, {8}, {16}, {24} } } }, /* SVGA3D_X8R8G8B8 */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {8} } },
- {{{0}, {8}, {16}, {24} } } }, /* SVGA3D_A8R8G8B8 */
-
- {SVGA3DBLOCKDESC_RGB,
- {1, 1, 1}, 2, 2, {16, {{5}, {6}, {5}, {0} } },
- {{{0}, {5}, {11}, {0} } } }, /* SVGA3D_R5G6B5 */
-
- {SVGA3DBLOCKDESC_RGB,
- {1, 1, 1}, 2, 2, {15, {{5}, {5}, {5}, {0} } },
- {{{0}, {5}, {10}, {0} } } }, /* SVGA3D_X1R5G5B5 */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 2, 2, {16, {{5}, {5}, {5}, {1} } },
- {{{0}, {5}, {10}, {15} } } }, /* SVGA3D_A1R5G5B5 */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 2, 2, {16, {{4}, {4}, {4}, {4} } },
- {{{0}, {4}, {8}, {12} } } }, /* SVGA3D_A4R4G4B4 */
-
- {SVGA3DBLOCKDESC_DEPTH,
- {1, 1, 1}, 4, 4, {32, {{0}, {0}, {32}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_Z_D32 */
-
- {SVGA3DBLOCKDESC_DEPTH,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {16}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_Z_D16 */
-
- {SVGA3DBLOCKDESC_DS,
- {1, 1, 1}, 4, 4, {32, {{0}, {8}, {24}, {0} } },
- {{{0}, {24}, {0}, {0} } } }, /* SVGA3D_Z_D24S8 */
-
- {SVGA3DBLOCKDESC_DS,
- {1, 1, 1}, 2, 2, {16, {{0}, {1}, {15}, {0} } },
- {{{0}, {15}, {0}, {0} } } }, /* SVGA3D_Z_D15S1 */
-
- {SVGA3DBLOCKDESC_LUMINANCE,
- {1, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_LUMINANCE8 */
-
- {SVGA3DBLOCKDESC_LA,
- {1, 1, 1}, 1, 1, {8, {{0}, {0}, {4}, {4} } },
- {{{0}, {0}, {0}, {4} } } }, /* SVGA3D_LUMINANCE4_ALPHA4 */
-
- {SVGA3DBLOCKDESC_LUMINANCE,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {16}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_LUMINANCE16 */
-
- {SVGA3DBLOCKDESC_LA,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {8}, {8} } },
- {{{0}, {0}, {0}, {8} } } }, /* SVGA3D_LUMINANCE8_ALPHA8 */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 8, 8, {64, {{0}, {0}, {64}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_DXT1 */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_DXT2 */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_DXT3 */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_DXT4 */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_DXT5 */
-
- {SVGA3DBLOCKDESC_UV,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {8}, {8} } },
- {{{0}, {0}, {0}, {8} } } }, /* SVGA3D_BUMPU8V8 */
-
- {SVGA3DBLOCKDESC_UVL,
- {1, 1, 1}, 2, 2, {16, {{5}, {5}, {6}, {0} } },
- {{{11}, {6}, {0}, {0} } } }, /* SVGA3D_BUMPL6V5U5 */
-
- {SVGA3DBLOCKDESC_UVL,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {0} } },
- {{{16}, {8}, {0}, {0} } } }, /* SVGA3D_BUMPX8L8V8U8 */
-
- {SVGA3DBLOCKDESC_UVL,
- {1, 1, 1}, 3, 3, {24, {{8}, {8}, {8}, {0} } },
- {{{16}, {8}, {0}, {0} } } }, /* SVGA3D_BUMPL8V8U8 */
-
- {SVGA3DBLOCKDESC_RGBA_FP,
- {1, 1, 1}, 8, 8, {64, {{16}, {16}, {16}, {16} } },
- {{{32}, {16}, {0}, {48} } } }, /* SVGA3D_ARGB_S10E5 */
-
- {SVGA3DBLOCKDESC_RGBA_FP,
- {1, 1, 1}, 16, 16, {128, {{32}, {32}, {32}, {32} } },
- {{{64}, {32}, {0}, {96} } } }, /* SVGA3D_ARGB_S23E8 */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 4, 4, {32, {{10}, {10}, {10}, {2} } },
- {{{0}, {10}, {20}, {30} } } }, /* SVGA3D_A2R10G10B10 */
-
- {SVGA3DBLOCKDESC_UV,
- {1, 1, 1}, 2, 2, {16, {{8}, {8}, {0}, {0} } },
- {{{8}, {0}, {0}, {0} } } }, /* SVGA3D_V8U8 */
-
- {SVGA3DBLOCKDESC_UVWQ,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {8} } },
- {{{24}, {16}, {8}, {0} } } }, /* SVGA3D_Q8W8V8U8 */
-
- {SVGA3DBLOCKDESC_UV,
- {1, 1, 1}, 2, 2, {16, {{8}, {8}, {0}, {0} } },
- {{{8}, {0}, {0}, {0} } } }, /* SVGA3D_CxV8U8 */
-
- {SVGA3DBLOCKDESC_UVL,
- {1, 1, 1}, 4, 4, {24, {{8}, {8}, {8}, {0} } },
- {{{16}, {8}, {0}, {0} } } }, /* SVGA3D_X8L8V8U8 */
-
- {SVGA3DBLOCKDESC_UVWA,
- {1, 1, 1}, 4, 4, {32, {{10}, {10}, {10}, {2} } },
- {{{0}, {10}, {20}, {30} } } }, /* SVGA3D_A2W10V10U10 */
-
- {SVGA3DBLOCKDESC_ALPHA,
- {1, 1, 1}, 1, 1, {8, {{0}, {0}, {0}, {8} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_ALPHA8 */
-
- {SVGA3DBLOCKDESC_R_FP,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {16}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R_S10E5 */
-
- {SVGA3DBLOCKDESC_R_FP,
- {1, 1, 1}, 4, 4, {32, {{0}, {0}, {32}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R_S23E8 */
-
- {SVGA3DBLOCKDESC_RG_FP,
- {1, 1, 1}, 4, 4, {32, {{0}, {16}, {16}, {0} } },
- {{{0}, {16}, {0}, {0} } } }, /* SVGA3D_RG_S10E5 */
-
- {SVGA3DBLOCKDESC_RG_FP,
- {1, 1, 1}, 8, 8, {64, {{0}, {32}, {32}, {0} } },
- {{{0}, {32}, {0}, {0} } } }, /* SVGA3D_RG_S23E8 */
-
- {SVGA3DBLOCKDESC_BUFFER,
- {1, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BUFFER */
-
- {SVGA3DBLOCKDESC_DEPTH,
- {1, 1, 1}, 4, 4, {32, {{0}, {0}, {24}, {0} } },
- {{{0}, {24}, {0}, {0} } } }, /* SVGA3D_Z_D24X8 */
-
- {SVGA3DBLOCKDESC_UV,
- {1, 1, 1}, 4, 4, {32, {{16}, {16}, {0}, {0} } },
- {{{16}, {0}, {0}, {0} } } }, /* SVGA3D_V16U16 */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 4, 4, {32, {{0}, {16}, {16}, {0} } },
- {{{0}, {0}, {16}, {0} } } }, /* SVGA3D_G16R16 */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 8, 8, {64, {{16}, {16}, {16}, {16} } },
- {{{32}, {16}, {0}, {48} } } }, /* SVGA3D_A16B16G16R16 */
-
- {SVGA3DBLOCKDESC_YUV,
- {1, 1, 1}, 2, 2, {16, {{8}, {0}, {8}, {0} } },
- {{{0}, {0}, {8}, {0} } } }, /* SVGA3D_UYVY */
-
- {SVGA3DBLOCKDESC_YUV,
- {1, 1, 1}, 2, 2, {16, {{8}, {0}, {8}, {0} } },
- {{{8}, {0}, {0}, {0} } } }, /* SVGA3D_YUY2 */
-
- {SVGA3DBLOCKDESC_NV12,
- {2, 2, 1}, 6, 2, {48, {{0}, {0}, {48}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_NV12 */
-
- {SVGA3DBLOCKDESC_AYUV,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {8} } },
- {{{0}, {8}, {16}, {24} } } }, /* SVGA3D_AYUV */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 16, 16, {128, {{32}, {32}, {32}, {32} } },
- {{{64}, {32}, {0}, {96} } } }, /* SVGA3D_R32G32B32A32_TYPELESS */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 16, 16, {128, {{32}, {32}, {32}, {32} } },
- {{{64}, {32}, {0}, {96} } } }, /* SVGA3D_R32G32B32A32_UINT */
-
- {SVGA3DBLOCKDESC_UVWQ,
- {1, 1, 1}, 16, 16, {128, {{32}, {32}, {32}, {32} } },
- {{{64}, {32}, {0}, {96} } } }, /* SVGA3D_R32G32B32A32_SINT */
-
- {SVGA3DBLOCKDESC_RGB,
- {1, 1, 1}, 12, 12, {96, {{32}, {32}, {32}, {0} } },
- {{{64}, {32}, {0}, {0} } } }, /* SVGA3D_R32G32B32_TYPELESS */
-
- {SVGA3DBLOCKDESC_RGB_FP,
- {1, 1, 1}, 12, 12, {96, {{32}, {32}, {32}, {0} } },
- {{{64}, {32}, {0}, {0} } } }, /* SVGA3D_R32G32B32_FLOAT */
-
- {SVGA3DBLOCKDESC_RGB,
- {1, 1, 1}, 12, 12, {96, {{32}, {32}, {32}, {0} } },
- {{{64}, {32}, {0}, {0} } } }, /* SVGA3D_R32G32B32_UINT */
-
- {SVGA3DBLOCKDESC_UVW,
- {1, 1, 1}, 12, 12, {96, {{32}, {32}, {32}, {0} } },
- {{{64}, {32}, {0}, {0} } } }, /* SVGA3D_R32G32B32_SINT */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 8, 8, {64, {{16}, {16}, {16}, {16} } },
- {{{32}, {16}, {0}, {48} } } }, /* SVGA3D_R16G16B16A16_TYPELESS */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 8, 8, {64, {{16}, {16}, {16}, {16} } },
- {{{32}, {16}, {0}, {48} } } }, /* SVGA3D_R16G16B16A16_UINT */
-
- {SVGA3DBLOCKDESC_UVWQ,
- {1, 1, 1}, 8, 8, {64, {{16}, {16}, {16}, {16} } },
- {{{32}, {16}, {0}, {48} } } }, /* SVGA3D_R16G16B16A16_SNORM */
-
- {SVGA3DBLOCKDESC_UVWQ,
- {1, 1, 1}, 8, 8, {64, {{16}, {16}, {16}, {16} } },
- {{{32}, {16}, {0}, {48} } } }, /* SVGA3D_R16G16B16A16_SINT */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 8, 8, {64, {{0}, {32}, {32}, {0} } },
- {{{0}, {32}, {0}, {0} } } }, /* SVGA3D_R32G32_TYPELESS */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 8, 8, {64, {{0}, {32}, {32}, {0} } },
- {{{0}, {32}, {0}, {0} } } }, /* SVGA3D_R32G32_UINT */
-
- {SVGA3DBLOCKDESC_UV,
- {1, 1, 1}, 8, 8, {64, {{0}, {32}, {32}, {0} } },
- {{{0}, {32}, {0}, {0} } } }, /* SVGA3D_R32G32_SINT */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 8, 8, {64, {{0}, {8}, {32}, {0} } },
- {{{0}, {32}, {0}, {0} } } }, /* SVGA3D_R32G8X24_TYPELESS */
-
- {SVGA3DBLOCKDESC_DS,
- {1, 1, 1}, 8, 8, {64, {{0}, {8}, {32}, {0} } },
- {{{0}, {32}, {0}, {0} } } }, /* SVGA3D_D32_FLOAT_S8X24_UINT */
-
- {SVGA3DBLOCKDESC_R_FP,
- {1, 1, 1}, 8, 8, {64, {{0}, {0}, {32}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R32_FLOAT_X8_X24_TYPELESS */
-
- {SVGA3DBLOCKDESC_GREEN,
- {1, 1, 1}, 8, 8, {64, {{0}, {8}, {0}, {0} } },
- {{{0}, {32}, {0}, {0} } } }, /* SVGA3D_X32_TYPELESS_G8X24_UINT */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 4, 4, {32, {{10}, {10}, {10}, {2} } },
- {{{0}, {10}, {20}, {30} } } }, /* SVGA3D_R10G10B10A2_TYPELESS */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 4, 4, {32, {{10}, {10}, {10}, {2} } },
- {{{0}, {10}, {20}, {30} } } }, /* SVGA3D_R10G10B10A2_UINT */
-
- {SVGA3DBLOCKDESC_RGB_FP,
- {1, 1, 1}, 4, 4, {32, {{10}, {11}, {11}, {0} } },
- {{{0}, {10}, {21}, {0} } } }, /* SVGA3D_R11G11B10_FLOAT */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {8} } },
- {{{16}, {8}, {0}, {24} } } }, /* SVGA3D_R8G8B8A8_TYPELESS */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {8} } },
- {{{16}, {8}, {0}, {24} } } }, /* SVGA3D_R8G8B8A8_UNORM */
-
- {SVGA3DBLOCKDESC_RGBA_SRGB,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {8} } },
- {{{16}, {8}, {0}, {24} } } }, /* SVGA3D_R8G8B8A8_UNORM_SRGB */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {8} } },
- {{{16}, {8}, {0}, {24} } } }, /* SVGA3D_R8G8B8A8_UINT */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {8} } },
- {{{16}, {8}, {0}, {24} } } }, /* SVGA3D_R8G8B8A8_SINT */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 4, 4, {32, {{0}, {16}, {16}, {0} } },
- {{{0}, {16}, {0}, {0} } } }, /* SVGA3D_R16G16_TYPELESS */
-
- {SVGA3DBLOCKDESC_RG_FP,
- {1, 1, 1}, 4, 4, {32, {{0}, {16}, {16}, {0} } },
- {{{0}, {16}, {0}, {0} } } }, /* SVGA3D_R16G16_UINT */
-
- {SVGA3DBLOCKDESC_UV,
- {1, 1, 1}, 4, 4, {32, {{0}, {16}, {16}, {0} } },
- {{{0}, {16}, {0}, {0} } } }, /* SVGA3D_R16G16_SINT */
-
- {SVGA3DBLOCKDESC_RED,
- {1, 1, 1}, 4, 4, {32, {{0}, {0}, {32}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R32_TYPELESS */
-
- {SVGA3DBLOCKDESC_DEPTH,
- {1, 1, 1}, 4, 4, {32, {{0}, {0}, {32}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_D32_FLOAT */
-
- {SVGA3DBLOCKDESC_RED,
- {1, 1, 1}, 4, 4, {32, {{0}, {0}, {32}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R32_UINT */
-
- {SVGA3DBLOCKDESC_RED,
- {1, 1, 1}, 4, 4, {32, {{0}, {0}, {32}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R32_SINT */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 4, 4, {32, {{0}, {8}, {24}, {0} } },
- {{{0}, {24}, {0}, {0} } } }, /* SVGA3D_R24G8_TYPELESS */
-
- {SVGA3DBLOCKDESC_DS,
- {1, 1, 1}, 4, 4, {32, {{0}, {8}, {24}, {0} } },
- {{{0}, {24}, {0}, {0} } } }, /* SVGA3D_D24_UNORM_S8_UINT */
-
- {SVGA3DBLOCKDESC_RED,
- {1, 1, 1}, 4, 4, {32, {{0}, {0}, {24}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R24_UNORM_X8_TYPELESS */
-
- {SVGA3DBLOCKDESC_GREEN,
- {1, 1, 1}, 4, 4, {32, {{0}, {8}, {0}, {0} } },
- {{{0}, {24}, {0}, {0} } } }, /* SVGA3D_X24_TYPELESS_G8_UINT */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 2, 2, {16, {{0}, {8}, {8}, {0} } },
- {{{0}, {8}, {0}, {0} } } }, /* SVGA3D_R8G8_TYPELESS */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 2, 2, {16, {{0}, {8}, {8}, {0} } },
- {{{0}, {8}, {0}, {0} } } }, /* SVGA3D_R8G8_UNORM */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 2, 2, {16, {{0}, {8}, {8}, {0} } },
- {{{0}, {8}, {0}, {0} } } }, /* SVGA3D_R8G8_UINT */
-
- {SVGA3DBLOCKDESC_UV,
- {1, 1, 1}, 2, 2, {16, {{0}, {8}, {8}, {0} } },
- {{{0}, {8}, {0}, {0} } } }, /* SVGA3D_R8G8_SINT */
-
- {SVGA3DBLOCKDESC_RED,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {16}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R16_TYPELESS */
-
- {SVGA3DBLOCKDESC_RED,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {16}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R16_UNORM */
-
- {SVGA3DBLOCKDESC_RED,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {16}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R16_UINT */
-
- {SVGA3DBLOCKDESC_U,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {16}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R16_SNORM */
-
- {SVGA3DBLOCKDESC_U,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {16}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R16_SINT */
-
- {SVGA3DBLOCKDESC_RED,
- {1, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R8_TYPELESS */
-
- {SVGA3DBLOCKDESC_RED,
- {1, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R8_UNORM */
-
- {SVGA3DBLOCKDESC_RED,
- {1, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R8_UINT */
-
- {SVGA3DBLOCKDESC_U,
- {1, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R8_SNORM */
-
- {SVGA3DBLOCKDESC_U,
- {1, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R8_SINT */
-
- {SVGA3DBLOCKDESC_RED,
- {8, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R1_UNORM */
-
- {SVGA3DBLOCKDESC_RGBE,
- {1, 1, 1}, 4, 4, {32, {{9}, {9}, {9}, {5} } },
- {{{18}, {9}, {0}, {27} } } }, /* SVGA3D_R9G9B9E5_SHAREDEXP */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 2, 2, {16, {{0}, {8}, {8}, {0} } },
- {{{0}, {8}, {0}, {0} } } }, /* SVGA3D_R8G8_B8G8_UNORM */
-
- {SVGA3DBLOCKDESC_RG,
- {1, 1, 1}, 2, 2, {16, {{0}, {8}, {8}, {0} } },
- {{{0}, {8}, {0}, {0} } } }, /* SVGA3D_G8R8_G8B8_UNORM */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 8, 8, {64, {{0}, {0}, {64}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC1_TYPELESS */
-
- {SVGA3DBLOCKDESC_COMPRESSED_SRGB,
- {4, 4, 1}, 8, 8, {64, {{0}, {0}, {64}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC1_UNORM_SRGB */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC2_TYPELESS */
-
- {SVGA3DBLOCKDESC_COMPRESSED_SRGB,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC2_UNORM_SRGB */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC3_TYPELESS */
-
- {SVGA3DBLOCKDESC_COMPRESSED_SRGB,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC3_UNORM_SRGB */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 8, 8, {64, {{0}, {0}, {64}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC4_TYPELESS */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 8, 8, {64, {{0}, {0}, {64}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC4_UNORM */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 8, 8, {64, {{0}, {0}, {64}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC4_SNORM */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC5_TYPELESS */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC5_UNORM */
-
- {SVGA3DBLOCKDESC_COMPRESSED,
- {4, 4, 1}, 16, 16, {128, {{0}, {0}, {128}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_BC5_SNORM */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 4, 4, {32, {{10}, {10}, {10}, {2} } },
- {{{0}, {10}, {20}, {30} } } }, /* SVGA3D_R10G10B10_XR_BIAS_A2_UNORM */
-
- {SVGA3DBLOCKDESC_RGBA,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {8} } },
- {{{0}, {8}, {16}, {24} } } }, /* SVGA3D_B8G8R8A8_TYPELESS */
-
- {SVGA3DBLOCKDESC_RGBA_SRGB,
- {1, 1, 1}, 4, 4, {32, {{8}, {8}, {8}, {8} } },
- {{{0}, {8}, {16}, {24} } } }, /* SVGA3D_B8G8R8A8_UNORM_SRGB */
-
- {SVGA3DBLOCKDESC_RGB,
- {1, 1, 1}, 4, 4, {24, {{8}, {8}, {8}, {0} } },
- {{{0}, {8}, {16}, {24} } } }, /* SVGA3D_B8G8R8X8_TYPELESS */
-
- {SVGA3DBLOCKDESC_RGB_SRGB,
- {1, 1, 1}, 4, 4, {24, {{8}, {8}, {8}, {0} } },
- {{{0}, {8}, {16}, {24} } } }, /* SVGA3D_B8G8R8X8_UNORM_SRGB */
-
- {SVGA3DBLOCKDESC_DEPTH,
- {1, 1, 1}, 2, 2, {16, {{0}, {0}, {16}, {0} } },
- {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_Z_DF16 */
-
- {SVGA3DBLOCKDESC_DS,
- {1, 1, 1}, 4, 4, {32, {{0}, {8}, {24}, {0} } },
- {{{0}, {24}, {0}, {0} } } }, /* SVGA3D_Z_DF24 */
-
- {SVGA3DBLOCKDESC_DS,
- {1, 1, 1}, 4, 4, {32, {{0}, {8}, {24}, {0} } },
- {{{0}, {24}, {0}, {0} } } }, /* SVGA3D_Z_D24S8_INT */
-};
-
-static inline u32 clamped_umul32(u32 a, u32 b)
-{
- uint64_t tmp = (uint64_t) a*b;
- return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
-}
-
-static inline const struct svga3d_surface_desc *
-svga3dsurface_get_desc(SVGA3dSurfaceFormat format)
-{
- if (format < ARRAY_SIZE(svga3d_surface_descs))
- return &svga3d_surface_descs[format];
-
- return &svga3d_surface_descs[SVGA3D_FORMAT_INVALID];
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * svga3dsurface_get_mip_size --
- *
- * Given a base level size and the mip level, compute the size of
- * the mip level.
- *
- * Results:
- * See above.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static inline surf_size_struct
-svga3dsurface_get_mip_size(surf_size_struct base_level, u32 mip_level)
-{
- surf_size_struct size;
-
- size.width = max_t(u32, base_level.width >> mip_level, 1);
- size.height = max_t(u32, base_level.height >> mip_level, 1);
- size.depth = max_t(u32, base_level.depth >> mip_level, 1);
- return size;
-}
-
-static inline void
-svga3dsurface_get_size_in_blocks(const struct svga3d_surface_desc *desc,
- const surf_size_struct *pixel_size,
- surf_size_struct *block_size)
-{
- block_size->width = DIV_ROUND_UP(pixel_size->width,
- desc->block_size.width);
- block_size->height = DIV_ROUND_UP(pixel_size->height,
- desc->block_size.height);
- block_size->depth = DIV_ROUND_UP(pixel_size->depth,
- desc->block_size.depth);
-}
-
-static inline bool
-svga3dsurface_is_planar_surface(const struct svga3d_surface_desc *desc)
-{
- return (desc->block_desc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0;
-}
-
-static inline u32
-svga3dsurface_calculate_pitch(const struct svga3d_surface_desc *desc,
- const surf_size_struct *size)
-{
- u32 pitch;
- surf_size_struct blocks;
-
- svga3dsurface_get_size_in_blocks(desc, size, &blocks);
-
- pitch = blocks.width * desc->pitch_bytes_per_block;
-
- return pitch;
-}
-
-/*
- *-----------------------------------------------------------------------------
- *
- * svga3dsurface_get_image_buffer_size --
- *
- * Return the number of bytes of buffer space required to store
- * one image of a surface, optionally using the specified pitch.
- *
- * If pitch is zero, it is assumed that rows are tightly packed.
- *
- * This function is overflow-safe. If the result would have
- * overflowed, instead we return MAX_UINT32.
- *
- * Results:
- * Byte count.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static inline u32
-svga3dsurface_get_image_buffer_size(const struct svga3d_surface_desc *desc,
- const surf_size_struct *size,
- u32 pitch)
-{
- surf_size_struct image_blocks;
- u32 slice_size, total_size;
-
- svga3dsurface_get_size_in_blocks(desc, size, &image_blocks);
-
- if (svga3dsurface_is_planar_surface(desc)) {
- total_size = clamped_umul32(image_blocks.width,
- image_blocks.height);
- total_size = clamped_umul32(total_size, image_blocks.depth);
- total_size = clamped_umul32(total_size, desc->bytes_per_block);
- return total_size;
- }
-
- if (pitch == 0)
- pitch = svga3dsurface_calculate_pitch(desc, size);
-
- slice_size = clamped_umul32(image_blocks.height, pitch);
- total_size = clamped_umul32(slice_size, image_blocks.depth);
-
- return total_size;
-}
-
-static inline u32
-svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format,
- surf_size_struct base_level_size,
- u32 num_mip_levels,
- bool cubemap)
-{
- const struct svga3d_surface_desc *desc = svga3dsurface_get_desc(format);
- u32 total_size = 0;
- u32 mip;
-
- for (mip = 0; mip < num_mip_levels; mip++) {
- surf_size_struct size =
- svga3dsurface_get_mip_size(base_level_size, mip);
- total_size += svga3dsurface_get_image_buffer_size(desc,
- &size, 0);
- }
-
- if (cubemap)
- total_size *= SVGA3D_MAX_SURFACE_FACES;
-
- return total_size;
-}
-
-
-/**
- * svga3dsurface_get_pixel_offset - Compute the offset (in bytes) to a pixel
- * in an image (or volume).
- *
- * @width: The image width in pixels.
- * @height: The image height in pixels
- */
-static inline u32
-svga3dsurface_get_pixel_offset(SVGA3dSurfaceFormat format,
- u32 width, u32 height,
- u32 x, u32 y, u32 z)
-{
- const struct svga3d_surface_desc *desc = svga3dsurface_get_desc(format);
- const u32 bw = desc->block_size.width, bh = desc->block_size.height;
- const u32 bd = desc->block_size.depth;
- const u32 rowstride = DIV_ROUND_UP(width, bw) * desc->bytes_per_block;
- const u32 imgstride = DIV_ROUND_UP(height, bh) * rowstride;
- const u32 offset = (z / bd * imgstride +
- y / bh * rowstride +
- x / bw * desc->bytes_per_block);
- return offset;
-}
-
-
-static inline u32
-svga3dsurface_get_image_offset(SVGA3dSurfaceFormat format,
- surf_size_struct baseLevelSize,
- u32 numMipLevels,
- u32 face,
- u32 mip)
-
-{
- u32 offset;
- u32 mipChainBytes;
- u32 mipChainBytesToLevel;
- u32 i;
- const struct svga3d_surface_desc *desc;
- surf_size_struct mipSize;
- u32 bytes;
-
- desc = svga3dsurface_get_desc(format);
-
- mipChainBytes = 0;
- mipChainBytesToLevel = 0;
- for (i = 0; i < numMipLevels; i++) {
- mipSize = svga3dsurface_get_mip_size(baseLevelSize, i);
- bytes = svga3dsurface_get_image_buffer_size(desc, &mipSize, 0);
- mipChainBytes += bytes;
- if (i < mip)
- mipChainBytesToLevel += bytes;
- }
-
- offset = mipChainBytes * face + mipChainBytesToLevel;
-
- return offset;
-}
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
index 96dc84dc34d0..ef1109c8fec8 100644
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
+++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
@@ -248,12 +248,13 @@ void vmw_evict_flags(struct ttm_buffer_object *bo,
*placement = vmw_sys_placement;
}
+/**
+ * FIXME: Proper access checks on buffers.
+ */
+
static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp)
{
- struct ttm_object_file *tfile =
- vmw_fpriv((struct drm_file *)filp->private_data)->tfile;
-
- return vmw_user_dmabuf_verify_access(bo, tfile);
+ return 0;
}
static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
deleted file mode 100644
index 00ae0925aca8..000000000000
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/**************************************************************************
- *
- * Copyright © 2009-2012 VMware, Inc., Palo Alto, CA., USA
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-#include "vmwgfx_drv.h"
-#include "vmwgfx_resource_priv.h"
-#include "ttm/ttm_placement.h"
-
-struct vmw_user_context {
- struct ttm_base_object base;
- struct vmw_resource res;
-};
-
-static void vmw_user_context_free(struct vmw_resource *res);
-static struct vmw_resource *
-vmw_user_context_base_to_res(struct ttm_base_object *base);
-
-static uint64_t vmw_user_context_size;
-
-static const struct vmw_user_resource_conv user_context_conv = {
- .object_type = VMW_RES_CONTEXT,
- .base_obj_to_res = vmw_user_context_base_to_res,
- .res_free = vmw_user_context_free
-};
-
-const struct vmw_user_resource_conv *user_context_converter =
- &user_context_conv;
-
-
-static const struct vmw_res_func vmw_legacy_context_func = {
- .res_type = vmw_res_context,
- .needs_backup = false,
- .may_evict = false,
- .type_name = "legacy contexts",
- .backup_placement = NULL,
- .create = NULL,
- .destroy = NULL,
- .bind = NULL,
- .unbind = NULL
-};
-
-/**
- * Context management:
- */
-
-static void vmw_hw_context_destroy(struct vmw_resource *res)
-{
-
- struct vmw_private *dev_priv = res->dev_priv;
- struct {
- SVGA3dCmdHeader header;
- SVGA3dCmdDestroyContext body;
- } *cmd;
-
-
- vmw_execbuf_release_pinned_bo(dev_priv);
- cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
- if (unlikely(cmd == NULL)) {
- DRM_ERROR("Failed reserving FIFO space for surface "
- "destruction.\n");
- return;
- }
-
- cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DESTROY);
- cmd->header.size = cpu_to_le32(sizeof(cmd->body));
- cmd->body.cid = cpu_to_le32(res->id);
-
- vmw_fifo_commit(dev_priv, sizeof(*cmd));
- vmw_3d_resource_dec(dev_priv, false);
-}
-
-static int vmw_context_init(struct vmw_private *dev_priv,
- struct vmw_resource *res,
- void (*res_free) (struct vmw_resource *res))
-{
- int ret;
-
- struct {
- SVGA3dCmdHeader header;
- SVGA3dCmdDefineContext body;
- } *cmd;
-
- ret = vmw_resource_init(dev_priv, res, false,
- res_free, &vmw_legacy_context_func);
-
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed to allocate a resource id.\n");
- goto out_early;
- }
-
- if (unlikely(res->id >= SVGA3D_MAX_CONTEXT_IDS)) {
- DRM_ERROR("Out of hw context ids.\n");
- vmw_resource_unreference(&res);
- return -ENOMEM;
- }
-
- cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
- if (unlikely(cmd == NULL)) {
- DRM_ERROR("Fifo reserve failed.\n");
- vmw_resource_unreference(&res);
- return -ENOMEM;
- }
-
- cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DEFINE);
- cmd->header.size = cpu_to_le32(sizeof(cmd->body));
- cmd->body.cid = cpu_to_le32(res->id);
-
- vmw_fifo_commit(dev_priv, sizeof(*cmd));
- (void) vmw_3d_resource_inc(dev_priv, false);
- vmw_resource_activate(res, vmw_hw_context_destroy);
- return 0;
-
-out_early:
- if (res_free == NULL)
- kfree(res);
- else
- res_free(res);
- return ret;
-}
-
-struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv)
-{
- struct vmw_resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
- int ret;
-
- if (unlikely(res == NULL))
- return NULL;
-
- ret = vmw_context_init(dev_priv, res, NULL);
-
- return (ret == 0) ? res : NULL;
-}
-
-/**
- * User-space context management:
- */
-
-static struct vmw_resource *
-vmw_user_context_base_to_res(struct ttm_base_object *base)
-{
- return &(container_of(base, struct vmw_user_context, base)->res);
-}
-
-static void vmw_user_context_free(struct vmw_resource *res)
-{
- struct vmw_user_context *ctx =
- container_of(res, struct vmw_user_context, res);
- struct vmw_private *dev_priv = res->dev_priv;
-
- ttm_base_object_kfree(ctx, base);
- ttm_mem_global_free(vmw_mem_glob(dev_priv),
- vmw_user_context_size);
-}
-
-/**
- * This function is called when user space has no more references on the
- * base object. It releases the base-object's reference on the resource object.
- */
-
-static void vmw_user_context_base_release(struct ttm_base_object **p_base)
-{
- struct ttm_base_object *base = *p_base;
- struct vmw_user_context *ctx =
- container_of(base, struct vmw_user_context, base);
- struct vmw_resource *res = &ctx->res;
-
- *p_base = NULL;
- vmw_resource_unreference(&res);
-}
-
-int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
- struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
-
- return ttm_ref_object_base_unref(tfile, arg->cid, TTM_REF_USAGE);
-}
-
-int vmw_context_define_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct vmw_private *dev_priv = vmw_priv(dev);
- struct vmw_user_context *ctx;
- struct vmw_resource *res;
- struct vmw_resource *tmp;
- struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
- struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
- struct vmw_master *vmaster = vmw_master(file_priv->master);
- int ret;
-
-
- /*
- * Approximate idr memory usage with 128 bytes. It will be limited
- * by maximum number_of contexts anyway.
- */
-
- if (unlikely(vmw_user_context_size == 0))
- vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128;
-
- ret = ttm_read_lock(&vmaster->lock, true);
- if (unlikely(ret != 0))
- return ret;
-
- ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
- vmw_user_context_size,
- false, true);
- if (unlikely(ret != 0)) {
- if (ret != -ERESTARTSYS)
- DRM_ERROR("Out of graphics memory for context"
- " creation.\n");
- goto out_unlock;
- }
-
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (unlikely(ctx == NULL)) {
- ttm_mem_global_free(vmw_mem_glob(dev_priv),
- vmw_user_context_size);
- ret = -ENOMEM;
- goto out_unlock;
- }
-
- res = &ctx->res;
- ctx->base.shareable = false;
- ctx->base.tfile = NULL;
-
- /*
- * From here on, the destructor takes over resource freeing.
- */
-
- ret = vmw_context_init(dev_priv, res, vmw_user_context_free);
- if (unlikely(ret != 0))
- goto out_unlock;
-
- tmp = vmw_resource_reference(&ctx->res);
- ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT,
- &vmw_user_context_base_release, NULL);
-
- if (unlikely(ret != 0)) {
- vmw_resource_unreference(&tmp);
- goto out_err;
- }
-
- arg->cid = ctx->base.hash.key;
-out_err:
- vmw_resource_unreference(&res);
-out_unlock:
- ttm_read_unlock(&vmaster->lock);
- return ret;
-
-}
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
index 655d57f188d9..bd78257cba8b 100644
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
+++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
@@ -60,7 +60,7 @@ int vmw_dmabuf_to_placement(struct vmw_private *dev_priv,
if (unlikely(ret != 0))
return ret;
- vmw_execbuf_release_pinned_bo(dev_priv);
+ vmw_execbuf_release_pinned_bo(dev_priv, false, 0);
ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
if (unlikely(ret != 0))
@@ -105,7 +105,7 @@ int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv,
return ret;
if (pin)
- vmw_execbuf_release_pinned_bo(dev_priv);
+ vmw_execbuf_release_pinned_bo(dev_priv, false, 0);
ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
if (unlikely(ret != 0))
@@ -214,7 +214,8 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv,
return ret;
if (pin)
- vmw_execbuf_release_pinned_bo(dev_priv);
+ vmw_execbuf_release_pinned_bo(dev_priv, false, 0);
+
ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
if (unlikely(ret != 0))
goto err_unlock;
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 91581fd5004b..56973cd41735 100644
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -432,7 +432,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
struct vmw_private *dev_priv;
int ret;
uint32_t svga_id;
- enum vmw_res_type i;
dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
if (unlikely(dev_priv == NULL)) {
@@ -449,18 +448,15 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
mutex_init(&dev_priv->cmdbuf_mutex);
mutex_init(&dev_priv->release_mutex);
rwlock_init(&dev_priv->resource_lock);
-
- for (i = vmw_res_context; i < vmw_res_max; ++i) {
- idr_init(&dev_priv->res_idr[i]);
- INIT_LIST_HEAD(&dev_priv->res_lru[i]);
- }
-
+ idr_init(&dev_priv->context_idr);
+ idr_init(&dev_priv->surface_idr);
+ idr_init(&dev_priv->stream_idr);
mutex_init(&dev_priv->init_mutex);
init_waitqueue_head(&dev_priv->fence_queue);
init_waitqueue_head(&dev_priv->fifo_queue);
dev_priv->fence_queue_waiters = 0;
atomic_set(&dev_priv->fifo_queue_waiters, 0);
-
+ INIT_LIST_HEAD(&dev_priv->surface_lru);
dev_priv->used_memory_size = 0;
dev_priv->io_start = pci_resource_start(dev->pdev, 0);
@@ -674,9 +670,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
out_err1:
vmw_ttm_global_release(dev_priv);
out_err0:
- for (i = vmw_res_context; i < vmw_res_max; ++i)
- idr_destroy(&dev_priv->res_idr[i]);
-
+ idr_destroy(&dev_priv->surface_idr);
+ idr_destroy(&dev_priv->context_idr);
+ idr_destroy(&dev_priv->stream_idr);
kfree(dev_priv);
return ret;
}
@@ -684,12 +680,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
static int vmw_driver_unload(struct drm_device *dev)
{
struct vmw_private *dev_priv = vmw_priv(dev);
- enum vmw_res_type i;
unregister_pm_notifier(&dev_priv->pm_nb);
- if (dev_priv->ctx.res_ht_initialized)
- drm_ht_remove(&dev_priv->ctx.res_ht);
if (dev_priv->ctx.cmd_bounce)
vfree(dev_priv->ctx.cmd_bounce);
if (dev_priv->enable_fb) {
@@ -716,9 +709,9 @@ static int vmw_driver_unload(struct drm_device *dev)
(void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
(void)ttm_bo_device_release(&dev_priv->bdev);
vmw_ttm_global_release(dev_priv);
-
- for (i = vmw_res_context; i < vmw_res_max; ++i)
- idr_destroy(&dev_priv->res_idr[i]);
+ idr_destroy(&dev_priv->surface_idr);
+ idr_destroy(&dev_priv->context_idr);
+ idr_destroy(&dev_priv->stream_idr);
kfree(dev_priv);
@@ -942,7 +935,7 @@ static void vmw_master_drop(struct drm_device *dev,
vmw_fp->locked_master = drm_master_get(file_priv->master);
ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
- vmw_execbuf_release_pinned_bo(dev_priv);
+ vmw_execbuf_release_pinned_bo(dev_priv, false, 0);
if (unlikely((ret != 0))) {
DRM_ERROR("Unable to lock TTM at VT switch.\n");
@@ -994,8 +987,7 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
* This empties VRAM and unbinds all GMR bindings.
* Buffer contents is moved to swappable memory.
*/
- vmw_execbuf_release_pinned_bo(dev_priv);
- vmw_resource_evict_all(dev_priv);
+ vmw_execbuf_release_pinned_bo(dev_priv, false, 0);
ttm_bo_swapout_all(&dev_priv->bdev);
break;
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 13aeda71280e..7c6f6e3a3c81 100644
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -67,46 +67,31 @@ struct vmw_fpriv {
struct vmw_dma_buffer {
struct ttm_buffer_object base;
- struct list_head res_list;
+ struct list_head validate_list;
+ bool gmr_bound;
+ uint32_t cur_validate_node;
+ bool on_validate_list;
};
-/**
- * struct vmw_validate_buffer - Carries validation info about buffers.
- *
- * @base: Validation info for TTM.
- * @hash: Hash entry for quick lookup of the TTM buffer object.
- *
- * This structure contains also driver private validation info
- * on top of the info needed by TTM.
- */
-struct vmw_validate_buffer {
- struct ttm_validate_buffer base;
- struct drm_hash_item hash;
-};
-
-struct vmw_res_func;
struct vmw_resource {
struct kref kref;
struct vmw_private *dev_priv;
+ struct idr *idr;
int id;
+ enum ttm_object_type res_type;
bool avail;
- unsigned long backup_size;
- bool res_dirty; /* Protected by backup buffer reserved */
- bool backup_dirty; /* Protected by backup buffer reserved */
- struct vmw_dma_buffer *backup;
- unsigned long backup_offset;
- const struct vmw_res_func *func;
- struct list_head lru_head; /* Protected by the resource lock */
- struct list_head mob_head; /* Protected by @backup reserved */
- void (*res_free) (struct vmw_resource *res);
+ void (*remove_from_lists) (struct vmw_resource *res);
void (*hw_destroy) (struct vmw_resource *res);
-};
-
-enum vmw_res_type {
- vmw_res_context,
- vmw_res_surface,
- vmw_res_stream,
- vmw_res_max
+ void (*res_free) (struct vmw_resource *res);
+ struct list_head validate_head;
+ struct list_head query_head; /* Protected by the cmdbuf mutex */
+ /* TODO is a generic snooper needed? */
+#if 0
+ void (*snoop)(struct vmw_resource *res,
+ struct ttm_object_file *tfile,
+ SVGA3dCmdHeader *header);
+ void *snoop_priv;
+#endif
};
struct vmw_cursor_snooper {
@@ -120,18 +105,20 @@ struct vmw_surface_offset;
struct vmw_surface {
struct vmw_resource res;
+ struct list_head lru_head; /* Protected by the resource lock */
uint32_t flags;
uint32_t format;
uint32_t mip_levels[DRM_VMW_MAX_SURFACE_FACES];
- struct drm_vmw_size base_size;
struct drm_vmw_size *sizes;
uint32_t num_sizes;
+
bool scanout;
+
/* TODO so far just a extra pointer */
struct vmw_cursor_snooper snooper;
+ struct ttm_buffer_object *backup;
struct vmw_surface_offset *offsets;
- SVGA3dTextureFilter autogen_filter;
- uint32_t multisample_count;
+ uint32_t backup_size;
};
struct vmw_marker_queue {
@@ -158,46 +145,29 @@ struct vmw_relocation {
uint32_t index;
};
-/**
- * struct vmw_res_cache_entry - resource information cache entry
- *
- * @valid: Whether the entry is valid, which also implies that the execbuf
- * code holds a reference to the resource, and it's placed on the
- * validation list.
- * @handle: User-space handle of a resource.
- * @res: Non-ref-counted pointer to the resource.
- *
- * Used to avoid frequent repeated user-space handle lookups of the
- * same resource.
- */
-struct vmw_res_cache_entry {
- bool valid;
- uint32_t handle;
- struct vmw_resource *res;
- struct vmw_resource_val_node *node;
-};
-
struct vmw_sw_context{
- struct drm_open_hash res_ht;
- bool res_ht_initialized;
+ struct ida bo_list;
+ uint32_t last_cid;
+ bool cid_valid;
bool kernel; /**< is the called made from the kernel */
+ struct vmw_resource *cur_ctx;
+ uint32_t last_sid;
+ uint32_t sid_translation;
+ bool sid_valid;
struct ttm_object_file *tfile;
struct list_head validate_nodes;
struct vmw_relocation relocs[VMWGFX_MAX_RELOCATIONS];
uint32_t cur_reloc;
- struct vmw_validate_buffer val_bufs[VMWGFX_MAX_VALIDATIONS];
+ struct ttm_validate_buffer val_bufs[VMWGFX_MAX_VALIDATIONS];
uint32_t cur_val_buf;
uint32_t *cmd_bounce;
uint32_t cmd_bounce_size;
struct list_head resource_list;
uint32_t fence_flags;
+ struct list_head query_list;
struct ttm_buffer_object *cur_query_bo;
- struct list_head res_relocations;
- uint32_t *buf_start;
- struct vmw_res_cache_entry res_cache[vmw_res_max];
- struct vmw_resource *last_query_ctx;
- bool needs_post_query_barrier;
- struct vmw_resource *error_resource;
+ uint32_t cur_query_cid;
+ bool query_cid_valid;
};
struct vmw_legacy_display;
@@ -272,7 +242,10 @@ struct vmw_private {
*/
rwlock_t resource_lock;
- struct idr res_idr[vmw_res_max];
+ struct idr context_idr;
+ struct idr surface_idr;
+ struct idr stream_idr;
+
/*
* Block lastclose from racing with firstopen.
*/
@@ -347,7 +320,6 @@ struct vmw_private {
struct ttm_buffer_object *dummy_query_bo;
struct ttm_buffer_object *pinned_bo;
uint32_t query_cid;
- uint32_t query_cid_valid;
bool dummy_query_bo_pinned;
/*
@@ -357,15 +329,10 @@ struct vmw_private {
* protected by the cmdbuf mutex for simplicity.
*/
- struct list_head res_lru[vmw_res_max];
+ struct list_head surface_lru;
uint32_t used_memory_size;
};
-static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res)
-{
- return container_of(res, struct vmw_surface, res);
-}
-
static inline struct vmw_private *vmw_priv(struct drm_device *dev)
{
return (struct vmw_private *)dev->dev_private;
@@ -414,16 +381,10 @@ extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);
/**
* Resource utilities - vmwgfx_resource.c
*/
-struct vmw_user_resource_conv;
-extern const struct vmw_user_resource_conv *user_surface_converter;
-extern const struct vmw_user_resource_conv *user_context_converter;
extern struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv);
extern void vmw_resource_unreference(struct vmw_resource **p_res);
extern struct vmw_resource *vmw_resource_reference(struct vmw_resource *res);
-extern int vmw_resource_validate(struct vmw_resource *res);
-extern int vmw_resource_reserve(struct vmw_resource *res, bool no_backup);
-extern bool vmw_resource_needs_backup(const struct vmw_resource *res);
extern int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_context_define_ioctl(struct drm_device *dev, void *data,
@@ -437,13 +398,14 @@ extern int vmw_user_lookup_handle(struct vmw_private *dev_priv,
uint32_t handle,
struct vmw_surface **out_surf,
struct vmw_dma_buffer **out_buf);
-extern int vmw_user_resource_lookup_handle(
- struct vmw_private *dev_priv,
- struct ttm_object_file *tfile,
- uint32_t handle,
- const struct vmw_user_resource_conv *converter,
- struct vmw_resource **p_res);
extern void vmw_surface_res_free(struct vmw_resource *res);
+extern int vmw_surface_init(struct vmw_private *dev_priv,
+ struct vmw_surface *srf,
+ void (*res_free) (struct vmw_resource *res));
+extern int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv,
+ struct ttm_object_file *tfile,
+ uint32_t handle,
+ struct vmw_surface **out);
extern int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
@@ -461,8 +423,6 @@ extern int vmw_dmabuf_init(struct vmw_private *dev_priv,
size_t size, struct ttm_placement *placement,
bool interuptable,
void (*bo_free) (struct ttm_buffer_object *bo));
-extern int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo,
- struct ttm_object_file *tfile);
extern int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
@@ -480,14 +440,7 @@ extern int vmw_user_stream_lookup(struct vmw_private *dev_priv,
struct ttm_object_file *tfile,
uint32_t *inout_id,
struct vmw_resource **out);
-extern void vmw_resource_unreserve(struct vmw_resource *res,
- struct vmw_dma_buffer *new_backup,
- unsigned long new_backup_offset);
-extern void vmw_resource_move_notify(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *mem);
-extern void vmw_fence_single_bo(struct ttm_buffer_object *bo,
- struct vmw_fence_obj *fence);
-extern void vmw_resource_evict_all(struct vmw_private *dev_priv);
+extern void vmw_resource_unreserve(struct list_head *list);
/**
* DMA buffer helper routines - vmwgfx_dmabuf.c
@@ -585,9 +538,10 @@ extern int vmw_execbuf_process(struct drm_file *file_priv,
struct drm_vmw_fence_rep __user
*user_fence_rep,
struct vmw_fence_obj **out_fence);
-extern void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
- struct vmw_fence_obj *fence);
-extern void vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv);
+
+extern void
+vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
+ bool only_on_cid_match, uint32_t cid);
extern int vmw_execbuf_fence_commands(struct drm_file *file_priv,
struct vmw_private *dev_priv,
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 534c96703c3f..e5775a0db495 100644
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -30,181 +30,6 @@
#include
#include
-#define VMW_RES_HT_ORDER 12
-
-/**
- * struct vmw_resource_relocation - Relocation info for resources
- *
- * @head: List head for the software context's relocation list.
- * @res: Non-ref-counted pointer to the resource.
- * @offset: Offset of 4 byte entries into the command buffer where the
- * id that needs fixup is located.
- */
-struct vmw_resource_relocation {
- struct list_head head;
- const struct vmw_resource *res;
- unsigned long offset;
-};
-
-/**
- * struct vmw_resource_val_node - Validation info for resources
- *
- * @head: List head for the software context's resource list.
- * @hash: Hash entry for quick resouce to val_node lookup.
- * @res: Ref-counted pointer to the resource.
- * @switch_backup: Boolean whether to switch backup buffer on unreserve.
- * @new_backup: Refcounted pointer to the new backup buffer.
- * @new_backup_offset: New backup buffer offset if @new_backup is non-NUll.
- * @first_usage: Set to true the first time the resource is referenced in
- * the command stream.
- * @no_buffer_needed: Resources do not need to allocate buffer backup on
- * reservation. The command stream will provide one.
- */
-struct vmw_resource_val_node {
- struct list_head head;
- struct drm_hash_item hash;
- struct vmw_resource *res;
- struct vmw_dma_buffer *new_backup;
- unsigned long new_backup_offset;
- bool first_usage;
- bool no_buffer_needed;
-};
-
-/**
- * vmw_resource_unreserve - unreserve resources previously reserved for
- * command submission.
- *
- * @list_head: list of resources to unreserve.
- * @backoff: Whether command submission failed.
- */
-static void vmw_resource_list_unreserve(struct list_head *list,
- bool backoff)
-{
- struct vmw_resource_val_node *val;
-
- list_for_each_entry(val, list, head) {
- struct vmw_resource *res = val->res;
- struct vmw_dma_buffer *new_backup =
- backoff ? NULL : val->new_backup;
-
- vmw_resource_unreserve(res, new_backup,
- val->new_backup_offset);
- vmw_dmabuf_unreference(&val->new_backup);
- }
-}
-
-
-/**
- * vmw_resource_val_add - Add a resource to the software context's
- * resource list if it's not already on it.
- *
- * @sw_context: Pointer to the software context.
- * @res: Pointer to the resource.
- * @p_node On successful return points to a valid pointer to a
- * struct vmw_resource_val_node, if non-NULL on entry.
- */
-static int vmw_resource_val_add(struct vmw_sw_context *sw_context,
- struct vmw_resource *res,
- struct vmw_resource_val_node **p_node)
-{
- struct vmw_resource_val_node *node;
- struct drm_hash_item *hash;
- int ret;
-
- if (likely(drm_ht_find_item(&sw_context->res_ht, (unsigned long) res,
- &hash) == 0)) {
- node = container_of(hash, struct vmw_resource_val_node, hash);
- node->first_usage = false;
- if (unlikely(p_node != NULL))
- *p_node = node;
- return 0;
- }
-
- node = kzalloc(sizeof(*node), GFP_KERNEL);
- if (unlikely(node == NULL)) {
- DRM_ERROR("Failed to allocate a resource validation "
- "entry.\n");
- return -ENOMEM;
- }
-
- node->hash.key = (unsigned long) res;
- ret = drm_ht_insert_item(&sw_context->res_ht, &node->hash);
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed to initialize a resource validation "
- "entry.\n");
- kfree(node);
- return ret;
- }
- list_add_tail(&node->head, &sw_context->resource_list);
- node->res = vmw_resource_reference(res);
- node->first_usage = true;
-
- if (unlikely(p_node != NULL))
- *p_node = node;
-
- return 0;
-}
-
-/**
- * vmw_resource_relocation_add - Add a relocation to the relocation list
- *
- * @list: Pointer to head of relocation list.
- * @res: The resource.
- * @offset: Offset into the command buffer currently being parsed where the
- * id that needs fixup is located. Granularity is 4 bytes.
- */
-static int vmw_resource_relocation_add(struct list_head *list,
- const struct vmw_resource *res,
- unsigned long offset)
-{
- struct vmw_resource_relocation *rel;
-
- rel = kmalloc(sizeof(*rel), GFP_KERNEL);
- if (unlikely(rel == NULL)) {
- DRM_ERROR("Failed to allocate a resource relocation.\n");
- return -ENOMEM;
- }
-
- rel->res = res;
- rel->offset = offset;
- list_add_tail(&rel->head, list);
-
- return 0;
-}
-
-/**
- * vmw_resource_relocations_free - Free all relocations on a list
- *
- * @list: Pointer to the head of the relocation list.
- */
-static void vmw_resource_relocations_free(struct list_head *list)
-{
- struct vmw_resource_relocation *rel, *n;
-
- list_for_each_entry_safe(rel, n, list, head) {
- list_del(&rel->head);
- kfree(rel);
- }
-}
-
-/**
- * vmw_resource_relocations_apply - Apply all relocations on a list
- *
- * @cb: Pointer to the start of the command buffer bein patch. This need
- * not be the same buffer as the one being parsed when the relocation
- * list was built, but the contents must be the same modulo the
- * resource ids.
- * @list: Pointer to the head of the relocation list.
- */
-static void vmw_resource_relocations_apply(uint32_t *cb,
- struct list_head *list)
-{
- struct vmw_resource_relocation *rel;
-
- list_for_each_entry(rel, list, head)
- cb[rel->offset] = rel->res->id;
-}
-
static int vmw_cmd_invalid(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
@@ -219,11 +44,25 @@ static int vmw_cmd_ok(struct vmw_private *dev_priv,
return 0;
}
+static void vmw_resource_to_validate_list(struct vmw_sw_context *sw_context,
+ struct vmw_resource **p_res)
+{
+ struct vmw_resource *res = *p_res;
+
+ if (list_empty(&res->validate_head)) {
+ list_add_tail(&res->validate_head, &sw_context->resource_list);
+ *p_res = NULL;
+ } else
+ vmw_resource_unreference(p_res);
+}
+
/**
* vmw_bo_to_validate_list - add a bo to a validate list
*
* @sw_context: The software context used for this command submission batch.
* @bo: The buffer object to add.
+ * @fence_flags: Fence flags to be or'ed with any other fence flags for
+ * this buffer on this submission batch.
* @p_val_node: If non-NULL Will be updated with the validate node number
* on return.
*
@@ -235,37 +74,21 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
uint32_t *p_val_node)
{
uint32_t val_node;
- struct vmw_validate_buffer *vval_buf;
struct ttm_validate_buffer *val_buf;
- struct drm_hash_item *hash;
- int ret;
- if (likely(drm_ht_find_item(&sw_context->res_ht, (unsigned long) bo,
- &hash) == 0)) {
- vval_buf = container_of(hash, struct vmw_validate_buffer,
- hash);
- val_buf = &vval_buf->base;
- val_node = vval_buf - sw_context->val_bufs;
- } else {
- val_node = sw_context->cur_val_buf;
- if (unlikely(val_node >= VMWGFX_MAX_VALIDATIONS)) {
- DRM_ERROR("Max number of DMA buffers per submission "
- "exceeded.\n");
- return -EINVAL;
- }
- vval_buf = &sw_context->val_bufs[val_node];
- vval_buf->hash.key = (unsigned long) bo;
- ret = drm_ht_insert_item(&sw_context->res_ht, &vval_buf->hash);
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed to initialize a buffer validation "
- "entry.\n");
- return ret;
- }
- ++sw_context->cur_val_buf;
- val_buf = &vval_buf->base;
+ val_node = vmw_dmabuf_validate_node(bo, sw_context->cur_val_buf);
+
+ if (unlikely(val_node >= VMWGFX_MAX_VALIDATIONS)) {
+ DRM_ERROR("Max number of DMA buffers per submission"
+ " exceeded.\n");
+ return -EINVAL;
+ }
+
+ val_buf = &sw_context->val_bufs[val_node];
+ if (unlikely(val_node == sw_context->cur_val_buf)) {
val_buf->bo = ttm_bo_reference(bo);
- val_buf->reserved = false;
list_add_tail(&val_buf->head, &sw_context->validate_nodes);
+ ++sw_context->cur_val_buf;
}
sw_context->fence_flags |= DRM_VMW_FENCE_FLAG_EXEC;
@@ -276,174 +99,85 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
return 0;
}
-/**
- * vmw_resources_reserve - Reserve all resources on the sw_context's
- * resource list.
- *
- * @sw_context: Pointer to the software context.
- *
- * Note that since vmware's command submission currently is protected by
- * the cmdbuf mutex, no fancy deadlock avoidance is required for resources,
- * since only a single thread at once will attempt this.
- */
-static int vmw_resources_reserve(struct vmw_sw_context *sw_context)
+static int vmw_cmd_cid_check(struct vmw_private *dev_priv,
+ struct vmw_sw_context *sw_context,
+ SVGA3dCmdHeader *header)
{
- struct vmw_resource_val_node *val;
- int ret;
-
- list_for_each_entry(val, &sw_context->resource_list, head) {
- struct vmw_resource *res = val->res;
-
- ret = vmw_resource_reserve(res, val->no_buffer_needed);
- if (unlikely(ret != 0))
- return ret;
+ struct vmw_resource *ctx;
- if (res->backup) {
- struct ttm_buffer_object *bo = &res->backup->base;
+ struct vmw_cid_cmd {
+ SVGA3dCmdHeader header;
+ __le32 cid;
+ } *cmd;
+ int ret;
- ret = vmw_bo_to_validate_list
- (sw_context, bo, NULL);
+ cmd = container_of(header, struct vmw_cid_cmd, header);
+ if (likely(sw_context->cid_valid && cmd->cid == sw_context->last_cid))
+ return 0;
- if (unlikely(ret != 0))
- return ret;
- }
+ ret = vmw_context_check(dev_priv, sw_context->tfile, cmd->cid,
+ &ctx);
+ if (unlikely(ret != 0)) {
+ DRM_ERROR("Could not find or use context %u\n",
+ (unsigned) cmd->cid);
+ return ret;
}
- return 0;
-}
-/**
- * vmw_resources_validate - Validate all resources on the sw_context's
- * resource list.
- *
- * @sw_context: Pointer to the software context.
- *
- * Before this function is called, all resource backup buffers must have
- * been validated.
- */
-static int vmw_resources_validate(struct vmw_sw_context *sw_context)
-{
- struct vmw_resource_val_node *val;
- int ret;
-
- list_for_each_entry(val, &sw_context->resource_list, head) {
- struct vmw_resource *res = val->res;
+ sw_context->last_cid = cmd->cid;
+ sw_context->cid_valid = true;
+ sw_context->cur_ctx = ctx;
+ vmw_resource_to_validate_list(sw_context, &ctx);
- ret = vmw_resource_validate(res);
- if (unlikely(ret != 0)) {
- if (ret != -ERESTARTSYS)
- DRM_ERROR("Failed to validate resource.\n");
- return ret;
- }
- }
return 0;
}
-/**
- * vmw_cmd_res_check - Check that a resource is present and if so, put it
- * on the resource validate list unless it's already there.
- *
- * @dev_priv: Pointer to a device private structure.
- * @sw_context: Pointer to the software context.
- * @res_type: Resource type.
- * @converter: User-space visisble type specific information.
- * @id: Pointer to the location in the command buffer currently being
- * parsed from where the user-space resource id handle is located.
- */
-static int vmw_cmd_res_check(struct vmw_private *dev_priv,
+static int vmw_cmd_sid_check(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
- enum vmw_res_type res_type,
- const struct vmw_user_resource_conv *converter,
- uint32_t *id,
- struct vmw_resource_val_node **p_val)
+ uint32_t *sid)
{
- struct vmw_res_cache_entry *rcache =
- &sw_context->res_cache[res_type];
- struct vmw_resource *res;
- struct vmw_resource_val_node *node;
+ struct vmw_surface *srf;
int ret;
+ struct vmw_resource *res;
- if (*id == SVGA3D_INVALID_ID)
+ if (*sid == SVGA3D_INVALID_ID)
return 0;
- /*
- * Fastpath in case of repeated commands referencing the same
- * resource
- */
-
- if (likely(rcache->valid && *id == rcache->handle)) {
- const struct vmw_resource *res = rcache->res;
-
- rcache->node->first_usage = false;
- if (p_val)
- *p_val = rcache->node;
-
- return vmw_resource_relocation_add
- (&sw_context->res_relocations, res,
- id - sw_context->buf_start);
+ if (likely((sw_context->sid_valid &&
+ *sid == sw_context->last_sid))) {
+ *sid = sw_context->sid_translation;
+ return 0;
}
- ret = vmw_user_resource_lookup_handle(dev_priv,
- sw_context->tfile,
- *id,
- converter,
- &res);
+ ret = vmw_user_surface_lookup_handle(dev_priv,
+ sw_context->tfile,
+ *sid, &srf);
if (unlikely(ret != 0)) {
- DRM_ERROR("Could not find or use resource 0x%08x.\n",
- (unsigned) *id);
- dump_stack();
+ DRM_ERROR("Could ot find or use surface 0x%08x "
+ "address 0x%08lx\n",
+ (unsigned int) *sid,
+ (unsigned long) sid);
return ret;
}
- rcache->valid = true;
- rcache->res = res;
- rcache->handle = *id;
+ ret = vmw_surface_validate(dev_priv, srf);
+ if (unlikely(ret != 0)) {
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("Could not validate surface.\n");
+ vmw_surface_unreference(&srf);
+ return ret;
+ }
- ret = vmw_resource_relocation_add(&sw_context->res_relocations,
- res,
- id - sw_context->buf_start);
- if (unlikely(ret != 0))
- goto out_no_reloc;
+ sw_context->last_sid = *sid;
+ sw_context->sid_valid = true;
+ sw_context->sid_translation = srf->res.id;
+ *sid = sw_context->sid_translation;
- ret = vmw_resource_val_add(sw_context, res, &node);
- if (unlikely(ret != 0))
- goto out_no_reloc;
+ res = &srf->res;
+ vmw_resource_to_validate_list(sw_context, &res);
- rcache->node = node;
- if (p_val)
- *p_val = node;
- vmw_resource_unreference(&res);
return 0;
-
-out_no_reloc:
- BUG_ON(sw_context->error_resource != NULL);
- sw_context->error_resource = res;
-
- return ret;
}
-/**
- * vmw_cmd_cid_check - Check a command header for valid context information.
- *
- * @dev_priv: Pointer to a device private structure.
- * @sw_context: Pointer to the software context.
- * @header: A command header with an embedded user-space context handle.
- *
- * Convenience function: Call vmw_cmd_res_check with the user-space context
- * handle embedded in @header.
- */
-static int vmw_cmd_cid_check(struct vmw_private *dev_priv,
- struct vmw_sw_context *sw_context,
- SVGA3dCmdHeader *header)
-{
- struct vmw_cid_cmd {
- SVGA3dCmdHeader header;
- __le32 cid;
- } *cmd;
-
- cmd = container_of(header, struct vmw_cid_cmd, header);
- return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
- user_context_converter, &cmd->cid, NULL);
-}
static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
@@ -460,9 +194,7 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,
return ret;
cmd = container_of(header, struct vmw_sid_cmd, header);
- ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter,
- &cmd->body.target.sid, NULL);
+ ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.target.sid);
return ret;
}
@@ -477,14 +209,10 @@ static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,
int ret;
cmd = container_of(header, struct vmw_sid_cmd, header);
- ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter,
- &cmd->body.src.sid, NULL);
+ ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.src.sid);
if (unlikely(ret != 0))
return ret;
- return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter,
- &cmd->body.dest.sid, NULL);
+ return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.dest.sid);
}
static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,
@@ -498,14 +226,10 @@ static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,
int ret;
cmd = container_of(header, struct vmw_sid_cmd, header);
- ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter,
- &cmd->body.src.sid, NULL);
+ ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.src.sid);
if (unlikely(ret != 0))
return ret;
- return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter,
- &cmd->body.dest.sid, NULL);
+ return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.dest.sid);
}
static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv,
@@ -524,9 +248,7 @@ static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv,
return -EPERM;
}
- return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter,
- &cmd->body.srcImage.sid, NULL);
+ return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.srcImage.sid);
}
static int vmw_cmd_present_check(struct vmw_private *dev_priv,
@@ -546,15 +268,14 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv,
return -EPERM;
}
- return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter, &cmd->body.sid,
- NULL);
+ return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.sid);
}
/**
* vmw_query_bo_switch_prepare - Prepare to switch pinned buffer for queries.
*
* @dev_priv: The device private structure.
+ * @cid: The hardware context for the next query.
* @new_query_bo: The new buffer holding query results.
* @sw_context: The software context used for this command submission.
*
@@ -562,18 +283,18 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv,
* query results, and if another buffer currently is pinned for query
* results. If so, the function prepares the state of @sw_context for
* switching pinned buffers after successful submission of the current
- * command batch.
+ * command batch. It also checks whether we're using a new query context.
+ * In that case, it makes sure we emit a query barrier for the old
+ * context before the current query buffer is fenced.
*/
static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
+ uint32_t cid,
struct ttm_buffer_object *new_query_bo,
struct vmw_sw_context *sw_context)
{
- struct vmw_res_cache_entry *ctx_entry =
- &sw_context->res_cache[vmw_res_context];
int ret;
-
- BUG_ON(!ctx_entry->valid);
- sw_context->last_query_ctx = ctx_entry->res;
+ bool add_cid = false;
+ uint32_t cid_to_add;
if (unlikely(new_query_bo != sw_context->cur_query_bo)) {
@@ -583,7 +304,9 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
}
if (unlikely(sw_context->cur_query_bo != NULL)) {
- sw_context->needs_post_query_barrier = true;
+ BUG_ON(!sw_context->query_cid_valid);
+ add_cid = true;
+ cid_to_add = sw_context->cur_query_cid;
ret = vmw_bo_to_validate_list(sw_context,
sw_context->cur_query_bo,
NULL);
@@ -600,6 +323,27 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
}
+ if (unlikely(cid != sw_context->cur_query_cid &&
+ sw_context->query_cid_valid)) {
+ add_cid = true;
+ cid_to_add = sw_context->cur_query_cid;
+ }
+
+ sw_context->cur_query_cid = cid;
+ sw_context->query_cid_valid = true;
+
+ if (add_cid) {
+ struct vmw_resource *ctx = sw_context->cur_ctx;
+
+ if (list_empty(&ctx->query_head))
+ list_add_tail(&ctx->query_head,
+ &sw_context->query_list);
+ ret = vmw_bo_to_validate_list(sw_context,
+ dev_priv->dummy_query_bo,
+ NULL);
+ if (unlikely(ret != 0))
+ return ret;
+ }
return 0;
}
@@ -611,9 +355,10 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
* @sw_context: The software context used for this command submission batch.
*
* This function will check if we're switching query buffers, and will then,
+ * if no other query waits are issued this command submission batch,
* issue a dummy occlusion query wait used as a query barrier. When the fence
* object following that query wait has signaled, we are sure that all
- * preceding queries have finished, and the old query buffer can be unpinned.
+ * preseding queries have finished, and the old query buffer can be unpinned.
* However, since both the new query buffer and the old one are fenced with
* that fence, we can do an asynchronus unpin now, and be sure that the
* old query buffer won't be moved until the fence has signaled.
@@ -624,19 +369,20 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context)
{
+
+ struct vmw_resource *ctx, *next_ctx;
+ int ret;
+
/*
* The validate list should still hold references to all
* contexts here.
*/
- if (sw_context->needs_post_query_barrier) {
- struct vmw_res_cache_entry *ctx_entry =
- &sw_context->res_cache[vmw_res_context];
- struct vmw_resource *ctx;
- int ret;
+ list_for_each_entry_safe(ctx, next_ctx, &sw_context->query_list,
+ query_head) {
+ list_del_init(&ctx->query_head);
- BUG_ON(!ctx_entry->valid);
- ctx = ctx_entry->res;
+ BUG_ON(list_empty(&ctx->validate_head));
ret = vmw_fifo_emit_dummy_query(dev_priv, ctx->id);
@@ -650,46 +396,40 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv,
ttm_bo_unref(&dev_priv->pinned_bo);
}
- if (!sw_context->needs_post_query_barrier) {
- vmw_bo_pin(sw_context->cur_query_bo, true);
+ vmw_bo_pin(sw_context->cur_query_bo, true);
- /*
- * We pin also the dummy_query_bo buffer so that we
- * don't need to validate it when emitting
- * dummy queries in context destroy paths.
- */
+ /*
+ * We pin also the dummy_query_bo buffer so that we
+ * don't need to validate it when emitting
+ * dummy queries in context destroy paths.
+ */
- vmw_bo_pin(dev_priv->dummy_query_bo, true);
- dev_priv->dummy_query_bo_pinned = true;
+ vmw_bo_pin(dev_priv->dummy_query_bo, true);
+ dev_priv->dummy_query_bo_pinned = true;
- BUG_ON(sw_context->last_query_ctx == NULL);
- dev_priv->query_cid = sw_context->last_query_ctx->id;
- dev_priv->query_cid_valid = true;
- dev_priv->pinned_bo =
- ttm_bo_reference(sw_context->cur_query_bo);
- }
+ dev_priv->query_cid = sw_context->cur_query_cid;
+ dev_priv->pinned_bo =
+ ttm_bo_reference(sw_context->cur_query_bo);
}
}
/**
- * vmw_translate_guest_pointer - Prepare to translate a user-space buffer
- * handle to a valid SVGAGuestPtr
+ * vmw_query_switch_backoff - clear query barrier list
+ * @sw_context: The sw context used for this submission batch.
*
- * @dev_priv: Pointer to a device private structure.
- * @sw_context: The software context used for this command batch validation.
- * @ptr: Pointer to the user-space handle to be translated.
- * @vmw_bo_p: Points to a location that, on successful return will carry
- * a reference-counted pointer to the DMA buffer identified by the
- * user-space handle in @id.
+ * This function is used as part of an error path, where a previously
+ * set up list of query barriers needs to be cleared.
*
- * This function saves information needed to translate a user-space buffer
- * handle to a valid SVGAGuestPtr. The translation does not take place
- * immediately, but during a call to vmw_apply_relocations().
- * This function builds a relocation list and a list of buffers to validate.
- * The former needs to be freed using either vmw_apply_relocations() or
- * vmw_free_relocations(). The latter needs to be freed using
- * vmw_clear_validations.
*/
+static void vmw_query_switch_backoff(struct vmw_sw_context *sw_context)
+{
+ struct list_head *list, *next;
+
+ list_for_each_safe(list, next, &sw_context->query_list) {
+ list_del_init(list);
+ }
+}
+
static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGAGuestPtr *ptr,
@@ -731,37 +471,6 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
return ret;
}
-/**
- * vmw_cmd_begin_query - validate a SVGA_3D_CMD_BEGIN_QUERY command.
- *
- * @dev_priv: Pointer to a device private struct.
- * @sw_context: The software context used for this command submission.
- * @header: Pointer to the command header in the command stream.
- */
-static int vmw_cmd_begin_query(struct vmw_private *dev_priv,
- struct vmw_sw_context *sw_context,
- SVGA3dCmdHeader *header)
-{
- struct vmw_begin_query_cmd {
- SVGA3dCmdHeader header;
- SVGA3dCmdBeginQuery q;
- } *cmd;
-
- cmd = container_of(header, struct vmw_begin_query_cmd,
- header);
-
- return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
- user_context_converter, &cmd->q.cid,
- NULL);
-}
-
-/**
- * vmw_cmd_end_query - validate a SVGA_3D_CMD_END_QUERY command.
- *
- * @dev_priv: Pointer to a device private struct.
- * @sw_context: The software context used for this command submission.
- * @header: Pointer to the command header in the command stream.
- */
static int vmw_cmd_end_query(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
@@ -784,19 +493,13 @@ static int vmw_cmd_end_query(struct vmw_private *dev_priv,
if (unlikely(ret != 0))
return ret;
- ret = vmw_query_bo_switch_prepare(dev_priv, &vmw_bo->base, sw_context);
+ ret = vmw_query_bo_switch_prepare(dev_priv, cmd->q.cid,
+ &vmw_bo->base, sw_context);
vmw_dmabuf_unreference(&vmw_bo);
return ret;
}
-/*
- * vmw_cmd_wait_query - validate a SVGA_3D_CMD_WAIT_QUERY command.
- *
- * @dev_priv: Pointer to a device private struct.
- * @sw_context: The software context used for this command submission.
- * @header: Pointer to the command header in the command stream.
- */
static int vmw_cmd_wait_query(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header)
@@ -807,6 +510,7 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv,
SVGA3dCmdWaitForQuery q;
} *cmd;
int ret;
+ struct vmw_resource *ctx;
cmd = container_of(header, struct vmw_query_cmd, header);
ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
@@ -820,6 +524,16 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv,
return ret;
vmw_dmabuf_unreference(&vmw_bo);
+
+ /*
+ * This wait will act as a barrier for previous waits for this
+ * context.
+ */
+
+ ctx = sw_context->cur_ctx;
+ if (!list_empty(&ctx->query_head))
+ list_del_init(&ctx->query_head);
+
return 0;
}
@@ -828,12 +542,14 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
SVGA3dCmdHeader *header)
{
struct vmw_dma_buffer *vmw_bo = NULL;
+ struct ttm_buffer_object *bo;
struct vmw_surface *srf = NULL;
struct vmw_dma_cmd {
SVGA3dCmdHeader header;
SVGA3dCmdSurfaceDMA dma;
} *cmd;
int ret;
+ struct vmw_resource *res;
cmd = container_of(header, struct vmw_dma_cmd, header);
ret = vmw_translate_guest_ptr(dev_priv, sw_context,
@@ -842,20 +558,37 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
if (unlikely(ret != 0))
return ret;
- ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter, &cmd->dma.host.sid,
- NULL);
+ bo = &vmw_bo->base;
+ ret = vmw_user_surface_lookup_handle(dev_priv, sw_context->tfile,
+ cmd->dma.host.sid, &srf);
+ if (ret) {
+ DRM_ERROR("could not find surface\n");
+ goto out_no_reloc;
+ }
+
+ ret = vmw_surface_validate(dev_priv, srf);
if (unlikely(ret != 0)) {
- if (unlikely(ret != -ERESTARTSYS))
- DRM_ERROR("could not find surface for DMA.\n");
- goto out_no_surface;
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("Culd not validate surface.\n");
+ goto out_no_validate;
}
- srf = vmw_res_to_srf(sw_context->res_cache[vmw_res_surface].res);
+ /*
+ * Patch command stream with device SID.
+ */
+ cmd->dma.host.sid = srf->res.id;
+ vmw_kms_cursor_snoop(srf, sw_context->tfile, bo, header);
+
+ vmw_dmabuf_unreference(&vmw_bo);
+
+ res = &srf->res;
+ vmw_resource_to_validate_list(sw_context, &res);
- vmw_kms_cursor_snoop(srf, sw_context->tfile, &vmw_bo->base, header);
+ return 0;
-out_no_surface:
+out_no_validate:
+ vmw_surface_unreference(&srf);
+out_no_reloc:
vmw_dmabuf_unreference(&vmw_bo);
return ret;
}
@@ -888,9 +621,8 @@ static int vmw_cmd_draw(struct vmw_private *dev_priv,
}
for (i = 0; i < cmd->body.numVertexDecls; ++i, ++decl) {
- ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter,
- &decl->array.surfaceId, NULL);
+ ret = vmw_cmd_sid_check(dev_priv, sw_context,
+ &decl->array.surfaceId);
if (unlikely(ret != 0))
return ret;
}
@@ -904,9 +636,8 @@ static int vmw_cmd_draw(struct vmw_private *dev_priv,
range = (SVGA3dPrimitiveRange *) decl;
for (i = 0; i < cmd->body.numRanges; ++i, ++range) {
- ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter,
- &range->indexArray.surfaceId, NULL);
+ ret = vmw_cmd_sid_check(dev_priv, sw_context,
+ &range->indexArray.surfaceId);
if (unlikely(ret != 0))
return ret;
}
@@ -937,9 +668,8 @@ static int vmw_cmd_tex_state(struct vmw_private *dev_priv,
if (likely(cur_state->name != SVGA3D_TS_BIND_TEXTURE))
continue;
- ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
- user_surface_converter,
- &cur_state->value, NULL);
+ ret = vmw_cmd_sid_check(dev_priv, sw_context,
+ &cur_state->value);
if (unlikely(ret != 0))
return ret;
}
@@ -970,34 +700,6 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,
return ret;
}
-/**
- * vmw_cmd_set_shader - Validate an SVGA_3D_CMD_SET_SHADER
- * command
- *
- * @dev_priv: Pointer to a device private struct.
- * @sw_context: The software context being used for this batch.
- * @header: Pointer to the command header in the command stream.
- */
-static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
- struct vmw_sw_context *sw_context,
- SVGA3dCmdHeader *header)
-{
- struct vmw_set_shader_cmd {
- SVGA3dCmdHeader header;
- SVGA3dCmdSetShader body;
- } *cmd;
- int ret;
-
- cmd = container_of(header, struct vmw_set_shader_cmd,
- header);
-
- ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
- if (unlikely(ret != 0))
- return ret;
-
- return 0;
-}
-
static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
void *buf, uint32_t *size)
@@ -1071,20 +773,16 @@ static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = {
VMW_CMD_DEF(SVGA_3D_CMD_PRESENT, &vmw_cmd_present_check),
VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check),
- VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_set_shader),
+ VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw),
VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check),
- VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_begin_query),
+ VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_end_query),
VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_wait_query),
VMW_CMD_DEF(SVGA_3D_CMD_PRESENT_READBACK, &vmw_cmd_ok),
VMW_CMD_DEF(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN,
- &vmw_cmd_blt_surf_screen_check),
- VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE_V2, &vmw_cmd_invalid),
- VMW_CMD_DEF(SVGA_3D_CMD_GENERATE_MIPMAPS, &vmw_cmd_invalid),
- VMW_CMD_DEF(SVGA_3D_CMD_ACTIVATE_SURFACE, &vmw_cmd_invalid),
- VMW_CMD_DEF(SVGA_3D_CMD_DEACTIVATE_SURFACE, &vmw_cmd_invalid),
+ &vmw_cmd_blt_surf_screen_check)
};
static int vmw_cmd_check(struct vmw_private *dev_priv,
@@ -1131,8 +829,6 @@ static int vmw_cmd_check_all(struct vmw_private *dev_priv,
int32_t cur_size = size;
int ret;
- sw_context->buf_start = buf;
-
while (cur_size > 0) {
size = cur_size;
ret = vmw_cmd_check(dev_priv, sw_context, buf, &size);
@@ -1164,63 +860,43 @@ static void vmw_apply_relocations(struct vmw_sw_context *sw_context)
for (i = 0; i < sw_context->cur_reloc; ++i) {
reloc = &sw_context->relocs[i];
- validate = &sw_context->val_bufs[reloc->index].base;
+ validate = &sw_context->val_bufs[reloc->index];
bo = validate->bo;
- switch (bo->mem.mem_type) {
- case TTM_PL_VRAM:
+ if (bo->mem.mem_type == TTM_PL_VRAM) {
reloc->location->offset += bo->offset;
reloc->location->gmrId = SVGA_GMR_FRAMEBUFFER;
- break;
- case VMW_PL_GMR:
+ } else
reloc->location->gmrId = bo->mem.start;
- break;
- default:
- BUG();
- }
}
vmw_free_relocations(sw_context);
}
-/**
- * vmw_resource_list_unrefererence - Free up a resource list and unreference
- * all resources referenced by it.
- *
- * @list: The resource list.
- */
-static void vmw_resource_list_unreference(struct list_head *list)
-{
- struct vmw_resource_val_node *val, *val_next;
-
- /*
- * Drop references to resources held during command submission.
- */
-
- list_for_each_entry_safe(val, val_next, list, head) {
- list_del_init(&val->head);
- vmw_resource_unreference(&val->res);
- kfree(val);
- }
-}
-
static void vmw_clear_validations(struct vmw_sw_context *sw_context)
{
- struct vmw_validate_buffer *entry, *next;
- struct vmw_resource_val_node *val;
+ struct ttm_validate_buffer *entry, *next;
+ struct vmw_resource *res, *res_next;
/*
* Drop references to DMA buffers held during command submission.
*/
list_for_each_entry_safe(entry, next, &sw_context->validate_nodes,
- base.head) {
- list_del(&entry->base.head);
- ttm_bo_unref(&entry->base.bo);
- (void) drm_ht_remove_item(&sw_context->res_ht, &entry->hash);
+ head) {
+ list_del(&entry->head);
+ vmw_dmabuf_validate_clear(entry->bo);
+ ttm_bo_unref(&entry->bo);
sw_context->cur_val_buf--;
}
BUG_ON(sw_context->cur_val_buf != 0);
- list_for_each_entry(val, &sw_context->resource_list, head)
- (void) drm_ht_remove_item(&sw_context->res_ht, &val->hash);
+ /*
+ * Drop references to resources held during command submission.
+ */
+ vmw_resource_unreserve(&sw_context->resource_list);
+ list_for_each_entry_safe(res, res_next, &sw_context->resource_list,
+ validate_head) {
+ list_del_init(&res->validate_head);
+ vmw_resource_unreference(&res);
+ }
}
static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
@@ -1263,11 +939,11 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
static int vmw_validate_buffers(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context)
{
- struct vmw_validate_buffer *entry;
+ struct ttm_validate_buffer *entry;
int ret;
- list_for_each_entry(entry, &sw_context->validate_nodes, base.head) {
- ret = vmw_validate_single_buffer(dev_priv, entry->base.bo);
+ list_for_each_entry(entry, &sw_context->validate_nodes, head) {
+ ret = vmw_validate_single_buffer(dev_priv, entry->bo);
if (unlikely(ret != 0))
return ret;
}
@@ -1430,8 +1106,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,
{
struct vmw_sw_context *sw_context = &dev_priv->ctx;
struct vmw_fence_obj *fence = NULL;
- struct vmw_resource *error_resource;
- struct list_head resource_list;
uint32_t handle;
void *cmd;
int ret;
@@ -1461,33 +1135,24 @@ int vmw_execbuf_process(struct drm_file *file_priv,
sw_context->kernel = true;
sw_context->tfile = vmw_fpriv(file_priv)->tfile;
+ sw_context->cid_valid = false;
+ sw_context->sid_valid = false;
sw_context->cur_reloc = 0;
sw_context->cur_val_buf = 0;
sw_context->fence_flags = 0;
+ INIT_LIST_HEAD(&sw_context->query_list);
INIT_LIST_HEAD(&sw_context->resource_list);
sw_context->cur_query_bo = dev_priv->pinned_bo;
- sw_context->last_query_ctx = NULL;
- sw_context->needs_post_query_barrier = false;
- memset(sw_context->res_cache, 0, sizeof(sw_context->res_cache));
+ sw_context->cur_query_cid = dev_priv->query_cid;
+ sw_context->query_cid_valid = (dev_priv->pinned_bo != NULL);
+
INIT_LIST_HEAD(&sw_context->validate_nodes);
- INIT_LIST_HEAD(&sw_context->res_relocations);
- if (!sw_context->res_ht_initialized) {
- ret = drm_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER);
- if (unlikely(ret != 0))
- goto out_unlock;
- sw_context->res_ht_initialized = true;
- }
- INIT_LIST_HEAD(&resource_list);
ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands,
command_size);
if (unlikely(ret != 0))
goto out_err;
- ret = vmw_resources_reserve(sw_context);
- if (unlikely(ret != 0))
- goto out_err;
-
ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes);
if (unlikely(ret != 0))
goto out_err;
@@ -1496,31 +1161,24 @@ int vmw_execbuf_process(struct drm_file *file_priv,
if (unlikely(ret != 0))
goto out_err;
- ret = vmw_resources_validate(sw_context);
- if (unlikely(ret != 0))
- goto out_err;
+ vmw_apply_relocations(sw_context);
if (throttle_us) {
ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue,
throttle_us);
if (unlikely(ret != 0))
- goto out_err;
+ goto out_throttle;
}
cmd = vmw_fifo_reserve(dev_priv, command_size);
if (unlikely(cmd == NULL)) {
DRM_ERROR("Failed reserving fifo space for commands.\n");
ret = -ENOMEM;
- goto out_err;
+ goto out_throttle;
}
- vmw_apply_relocations(sw_context);
memcpy(cmd, kernel_commands, command_size);
-
- vmw_resource_relocations_apply(cmd, &sw_context->res_relocations);
- vmw_resource_relocations_free(&sw_context->res_relocations);
-
vmw_fifo_commit(dev_priv, command_size);
vmw_query_bo_switch_commit(dev_priv, sw_context);
@@ -1536,14 +1194,9 @@ int vmw_execbuf_process(struct drm_file *file_priv,
if (ret != 0)
DRM_ERROR("Fence submission error. Syncing.\n");
- vmw_resource_list_unreserve(&sw_context->resource_list, false);
ttm_eu_fence_buffer_objects(&sw_context->validate_nodes,
(void *) fence);
- if (unlikely(dev_priv->pinned_bo != NULL &&
- !dev_priv->query_cid_valid))
- __vmw_execbuf_release_pinned_bo(dev_priv, fence);
-
vmw_clear_validations(sw_context);
vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
user_fence_rep, fence, handle);
@@ -1556,40 +1209,17 @@ int vmw_execbuf_process(struct drm_file *file_priv,
vmw_fence_obj_unreference(&fence);
}
- list_splice_init(&sw_context->resource_list, &resource_list);
mutex_unlock(&dev_priv->cmdbuf_mutex);
-
- /*
- * Unreference resources outside of the cmdbuf_mutex to
- * avoid deadlocks in resource destruction paths.
- */
- vmw_resource_list_unreference(&resource_list);
-
return 0;
out_err:
- vmw_resource_relocations_free(&sw_context->res_relocations);
vmw_free_relocations(sw_context);
+out_throttle:
+ vmw_query_switch_backoff(sw_context);
ttm_eu_backoff_reservation(&sw_context->validate_nodes);
- vmw_resource_list_unreserve(&sw_context->resource_list, true);
vmw_clear_validations(sw_context);
- if (unlikely(dev_priv->pinned_bo != NULL &&
- !dev_priv->query_cid_valid))
- __vmw_execbuf_release_pinned_bo(dev_priv, NULL);
out_unlock:
- list_splice_init(&sw_context->resource_list, &resource_list);
- error_resource = sw_context->error_resource;
- sw_context->error_resource = NULL;
mutex_unlock(&dev_priv->cmdbuf_mutex);
-
- /*
- * Unreference resources outside of the cmdbuf_mutex to
- * avoid deadlocks in resource destruction paths.
- */
- vmw_resource_list_unreference(&resource_list);
- if (unlikely(error_resource != NULL))
- vmw_resource_unreference(&error_resource);
-
return ret;
}
@@ -1614,13 +1244,13 @@ static void vmw_execbuf_unpin_panic(struct vmw_private *dev_priv)
/**
- * __vmw_execbuf_release_pinned_bo - Flush queries and unpin the pinned
+ * vmw_execbuf_release_pinned_bo - Flush queries and unpin the pinned
* query bo.
*
* @dev_priv: The device private structure.
- * @fence: If non-NULL should point to a struct vmw_fence_obj issued
- * _after_ a query barrier that flushes all queries touching the current
- * buffer pointed to by @dev_priv->pinned_bo
+ * @only_on_cid_match: Only flush and unpin if the current active query cid
+ * matches @cid.
+ * @cid: Optional context id to match.
*
* This function should be used to unpin the pinned query bo, or
* as a query barrier when we need to make sure that all queries have
@@ -1633,21 +1263,23 @@ static void vmw_execbuf_unpin_panic(struct vmw_private *dev_priv)
*
* The function will synchronize on the previous query barrier, and will
* thus not finish until that barrier has executed.
- *
- * the @dev_priv->cmdbuf_mutex needs to be held by the current thread
- * before calling this function.
*/
-void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
- struct vmw_fence_obj *fence)
+void vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
+ bool only_on_cid_match, uint32_t cid)
{
int ret = 0;
struct list_head validate_list;
struct ttm_validate_buffer pinned_val, query_val;
- struct vmw_fence_obj *lfence = NULL;
+ struct vmw_fence_obj *fence;
+
+ mutex_lock(&dev_priv->cmdbuf_mutex);
if (dev_priv->pinned_bo == NULL)
goto out_unlock;
+ if (only_on_cid_match && cid != dev_priv->query_cid)
+ goto out_unlock;
+
INIT_LIST_HEAD(&validate_list);
pinned_val.bo = ttm_bo_reference(dev_priv->pinned_bo);
@@ -1665,34 +1297,25 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
goto out_no_reserve;
}
- if (dev_priv->query_cid_valid) {
- BUG_ON(fence != NULL);
- ret = vmw_fifo_emit_dummy_query(dev_priv, dev_priv->query_cid);
- if (unlikely(ret != 0)) {
- vmw_execbuf_unpin_panic(dev_priv);
- goto out_no_emit;
- }
- dev_priv->query_cid_valid = false;
+ ret = vmw_fifo_emit_dummy_query(dev_priv, dev_priv->query_cid);
+ if (unlikely(ret != 0)) {
+ vmw_execbuf_unpin_panic(dev_priv);
+ goto out_no_emit;
}
vmw_bo_pin(dev_priv->pinned_bo, false);
vmw_bo_pin(dev_priv->dummy_query_bo, false);
dev_priv->dummy_query_bo_pinned = false;
- if (fence == NULL) {
- (void) vmw_execbuf_fence_commands(NULL, dev_priv, &lfence,
- NULL);
- fence = lfence;
- }
+ (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
ttm_eu_fence_buffer_objects(&validate_list, (void *) fence);
- if (lfence != NULL)
- vmw_fence_obj_unreference(&lfence);
ttm_bo_unref(&query_val.bo);
ttm_bo_unref(&pinned_val.bo);
ttm_bo_unref(&dev_priv->pinned_bo);
out_unlock:
+ mutex_unlock(&dev_priv->cmdbuf_mutex);
return;
out_no_emit:
@@ -1701,31 +1324,6 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
ttm_bo_unref(&query_val.bo);
ttm_bo_unref(&pinned_val.bo);
ttm_bo_unref(&dev_priv->pinned_bo);
-}
-
-/**
- * vmw_execbuf_release_pinned_bo - Flush queries and unpin the pinned
- * query bo.
- *
- * @dev_priv: The device private structure.
- *
- * This function should be used to unpin the pinned query bo, or
- * as a query barrier when we need to make sure that all queries have
- * finished before the next fifo command. (For example on hardware
- * context destructions where the hardware may otherwise leak unfinished
- * queries).
- *
- * This function does not return any failure codes, but make attempts
- * to do safe unpinning in case of errors.
- *
- * The function will synchronize on the previous query barrier, and will
- * thus not finish until that barrier has executed.
- */
-void vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv)
-{
- mutex_lock(&dev_priv->cmdbuf_mutex);
- if (dev_priv->query_cid_valid)
- __vmw_execbuf_release_pinned_bo(dev_priv, NULL);
mutex_unlock(&dev_priv->cmdbuf_mutex);
}
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index c62d20e8a6f1..bc187fafd58c 100644
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -537,7 +537,7 @@ static void vmw_user_fence_destroy(struct vmw_fence_obj *fence)
container_of(fence, struct vmw_user_fence, fence);
struct vmw_fence_manager *fman = fence->fman;
- ttm_base_object_kfree(ufence, base);
+ kfree(ufence);
/*
* Free kernel space accounting.
*/
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 2f7c08ebf568..b07ca2e4d04b 100644
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -131,7 +131,6 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
struct drm_vmw_rect *clips = NULL;
struct drm_mode_object *obj;
struct vmw_framebuffer *vfb;
- struct vmw_resource *res;
uint32_t num_clips;
int ret;
@@ -179,13 +178,11 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
if (unlikely(ret != 0))
goto out_no_ttm_lock;
- ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg->sid,
- user_surface_converter,
- &res);
+ ret = vmw_user_surface_lookup_handle(dev_priv, tfile, arg->sid,
+ &surface);
if (ret)
goto out_no_surface;
- surface = vmw_res_to_srf(res);
ret = vmw_kms_present(dev_priv, file_priv,
vfb, surface, arg->sid,
arg->dest_x, arg->dest_y,
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 0def4ff5b621..292c988c54ea 100644
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -30,7 +30,17 @@
#include
#include
#include
-#include "vmwgfx_resource_priv.h"
+
+struct vmw_user_context {
+ struct ttm_base_object base;
+ struct vmw_resource res;
+};
+
+struct vmw_user_surface {
+ struct ttm_base_object base;
+ struct vmw_surface srf;
+ uint32_t size;
+};
struct vmw_user_dma_buffer {
struct ttm_base_object base;
@@ -52,21 +62,17 @@ struct vmw_user_stream {
struct vmw_stream stream;
};
+struct vmw_surface_offset {
+ uint32_t face;
+ uint32_t mip;
+ uint32_t bo_offset;
+};
+
+static uint64_t vmw_user_context_size;
+static uint64_t vmw_user_surface_size;
static uint64_t vmw_user_stream_size;
-static const struct vmw_res_func vmw_stream_func = {
- .res_type = vmw_res_stream,
- .needs_backup = false,
- .may_evict = false,
- .type_name = "video streams",
- .backup_placement = NULL,
- .create = NULL,
- .destroy = NULL,
- .bind = NULL,
- .unbind = NULL
-};
-
static inline struct vmw_dma_buffer *
vmw_dma_buffer(struct ttm_buffer_object *bo)
{
@@ -94,14 +100,13 @@ struct vmw_resource *vmw_resource_reference(struct vmw_resource *res)
*
* Release the resource id to the resource id manager and set it to -1
*/
-void vmw_resource_release_id(struct vmw_resource *res)
+static void vmw_resource_release_id(struct vmw_resource *res)
{
struct vmw_private *dev_priv = res->dev_priv;
- struct idr *idr = &dev_priv->res_idr[res->func->res_type];
write_lock(&dev_priv->resource_lock);
if (res->id != -1)
- idr_remove(idr, res->id);
+ idr_remove(res->idr, res->id);
res->id = -1;
write_unlock(&dev_priv->resource_lock);
}
@@ -111,33 +116,17 @@ static void vmw_resource_release(struct kref *kref)
struct vmw_resource *res =
container_of(kref, struct vmw_resource, kref);
struct vmw_private *dev_priv = res->dev_priv;
- int id;
- struct idr *idr = &dev_priv->res_idr[res->func->res_type];
+ int id = res->id;
+ struct idr *idr = res->idr;
res->avail = false;
- list_del_init(&res->lru_head);
+ if (res->remove_from_lists != NULL)
+ res->remove_from_lists(res);
write_unlock(&dev_priv->resource_lock);
- if (res->backup) {
- struct ttm_buffer_object *bo = &res->backup->base;
-
- ttm_bo_reserve(bo, false, false, false, 0);
- if (!list_empty(&res->mob_head) &&
- res->func->unbind != NULL) {
- struct ttm_validate_buffer val_buf;
-
- val_buf.bo = bo;
- res->func->unbind(res, false, &val_buf);
- }
- res->backup_dirty = false;
- list_del_init(&res->mob_head);
- ttm_bo_unreserve(bo);
- vmw_dmabuf_unreference(&res->backup);
- }
if (likely(res->hw_destroy != NULL))
res->hw_destroy(res);
- id = res->id;
if (res->res_free != NULL)
res->res_free(res);
else
@@ -164,25 +153,25 @@ void vmw_resource_unreference(struct vmw_resource **p_res)
/**
* vmw_resource_alloc_id - release a resource id to the id manager.
*
+ * @dev_priv: Pointer to the device private structure.
* @res: Pointer to the resource.
*
* Allocate the lowest free resource from the resource manager, and set
* @res->id to that id. Returns 0 on success and -ENOMEM on failure.
*/
-int vmw_resource_alloc_id(struct vmw_resource *res)
+static int vmw_resource_alloc_id(struct vmw_private *dev_priv,
+ struct vmw_resource *res)
{
- struct vmw_private *dev_priv = res->dev_priv;
int ret;
- struct idr *idr = &dev_priv->res_idr[res->func->res_type];
BUG_ON(res->id != -1);
do {
- if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
+ if (unlikely(idr_pre_get(res->idr, GFP_KERNEL) == 0))
return -ENOMEM;
write_lock(&dev_priv->resource_lock);
- ret = idr_get_new_above(idr, res, 1, &res->id);
+ ret = idr_get_new_above(res->idr, res, 1, &res->id);
write_unlock(&dev_priv->resource_lock);
} while (ret == -EAGAIN);
@@ -190,39 +179,31 @@ int vmw_resource_alloc_id(struct vmw_resource *res)
return ret;
}
-/**
- * vmw_resource_init - initialize a struct vmw_resource
- *
- * @dev_priv: Pointer to a device private struct.
- * @res: The struct vmw_resource to initialize.
- * @obj_type: Resource object type.
- * @delay_id: Boolean whether to defer device id allocation until
- * the first validation.
- * @res_free: Resource destructor.
- * @func: Resource function table.
- */
-int vmw_resource_init(struct vmw_private *dev_priv, struct vmw_resource *res,
- bool delay_id,
- void (*res_free) (struct vmw_resource *res),
- const struct vmw_res_func *func)
+
+static int vmw_resource_init(struct vmw_private *dev_priv,
+ struct vmw_resource *res,
+ struct idr *idr,
+ enum ttm_object_type obj_type,
+ bool delay_id,
+ void (*res_free) (struct vmw_resource *res),
+ void (*remove_from_lists)
+ (struct vmw_resource *res))
{
kref_init(&res->kref);
res->hw_destroy = NULL;
res->res_free = res_free;
+ res->remove_from_lists = remove_from_lists;
+ res->res_type = obj_type;
+ res->idr = idr;
res->avail = false;
res->dev_priv = dev_priv;
- res->func = func;
- INIT_LIST_HEAD(&res->lru_head);
- INIT_LIST_HEAD(&res->mob_head);
+ INIT_LIST_HEAD(&res->query_head);
+ INIT_LIST_HEAD(&res->validate_head);
res->id = -1;
- res->backup = NULL;
- res->backup_offset = 0;
- res->backup_dirty = false;
- res->res_dirty = false;
if (delay_id)
return 0;
else
- return vmw_resource_alloc_id(res);
+ return vmw_resource_alloc_id(dev_priv, res);
}
/**
@@ -237,8 +218,9 @@ int vmw_resource_init(struct vmw_private *dev_priv, struct vmw_resource *res,
* Activate basically means that the function vmw_resource_lookup will
* find it.
*/
-void vmw_resource_activate(struct vmw_resource *res,
- void (*hw_destroy) (struct vmw_resource *))
+
+static void vmw_resource_activate(struct vmw_resource *res,
+ void (*hw_destroy) (struct vmw_resource *))
{
struct vmw_private *dev_priv = res->dev_priv;
@@ -268,245 +250,1392 @@ struct vmw_resource *vmw_resource_lookup(struct vmw_private *dev_priv,
}
/**
- * vmw_user_resource_lookup_handle - lookup a struct resource from a
- * TTM user-space handle and perform basic type checks
- *
- * @dev_priv: Pointer to a device private struct
- * @tfile: Pointer to a struct ttm_object_file identifying the caller
- * @handle: The TTM user-space handle
- * @converter: Pointer to an object describing the resource type
- * @p_res: On successful return the location pointed to will contain
- * a pointer to a refcounted struct vmw_resource.
- *
- * If the handle can't be found or is associated with an incorrect resource
- * type, -EINVAL will be returned.
+ * Context management:
*/
-int vmw_user_resource_lookup_handle(struct vmw_private *dev_priv,
- struct ttm_object_file *tfile,
- uint32_t handle,
- const struct vmw_user_resource_conv
- *converter,
- struct vmw_resource **p_res)
+
+static void vmw_hw_context_destroy(struct vmw_resource *res)
{
- struct ttm_base_object *base;
- struct vmw_resource *res;
- int ret = -EINVAL;
- base = ttm_base_object_lookup(tfile, handle);
- if (unlikely(base == NULL))
- return -EINVAL;
+ struct vmw_private *dev_priv = res->dev_priv;
+ struct {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdDestroyContext body;
+ } *cmd;
- if (unlikely(base->object_type != converter->object_type))
- goto out_bad_resource;
- res = converter->base_obj_to_res(base);
+ vmw_execbuf_release_pinned_bo(dev_priv, true, res->id);
- read_lock(&dev_priv->resource_lock);
- if (!res->avail || res->res_free != converter->res_free) {
- read_unlock(&dev_priv->resource_lock);
- goto out_bad_resource;
+ cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+ if (unlikely(cmd == NULL)) {
+ DRM_ERROR("Failed reserving FIFO space for surface "
+ "destruction.\n");
+ return;
}
- kref_get(&res->kref);
- read_unlock(&dev_priv->resource_lock);
-
- *p_res = res;
- ret = 0;
-
-out_bad_resource:
- ttm_base_object_unref(&base);
+ cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DESTROY);
+ cmd->header.size = cpu_to_le32(sizeof(cmd->body));
+ cmd->body.cid = cpu_to_le32(res->id);
- return ret;
+ vmw_fifo_commit(dev_priv, sizeof(*cmd));
+ vmw_3d_resource_dec(dev_priv, false);
}
-/**
- * Helper function that looks either a surface or dmabuf.
- *
- * The pointer this pointed at by out_surf and out_buf needs to be null.
- */
-int vmw_user_lookup_handle(struct vmw_private *dev_priv,
- struct ttm_object_file *tfile,
- uint32_t handle,
- struct vmw_surface **out_surf,
- struct vmw_dma_buffer **out_buf)
+static int vmw_context_init(struct vmw_private *dev_priv,
+ struct vmw_resource *res,
+ void (*res_free) (struct vmw_resource *res))
{
- struct vmw_resource *res;
int ret;
- BUG_ON(*out_surf || *out_buf);
+ struct {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdDefineContext body;
+ } *cmd;
- ret = vmw_user_resource_lookup_handle(dev_priv, tfile, handle,
- user_surface_converter,
- &res);
- if (!ret) {
- *out_surf = vmw_res_to_srf(res);
- return 0;
+ ret = vmw_resource_init(dev_priv, res, &dev_priv->context_idr,
+ VMW_RES_CONTEXT, false, res_free, NULL);
+
+ if (unlikely(ret != 0)) {
+ DRM_ERROR("Failed to allocate a resource id.\n");
+ goto out_early;
}
- *out_surf = NULL;
- ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf);
- return ret;
-}
+ if (unlikely(res->id >= SVGA3D_MAX_CONTEXT_IDS)) {
+ DRM_ERROR("Out of hw context ids.\n");
+ vmw_resource_unreference(&res);
+ return -ENOMEM;
+ }
-/**
- * Buffer management.
- */
-void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
-{
- struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
+ cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+ if (unlikely(cmd == NULL)) {
+ DRM_ERROR("Fifo reserve failed.\n");
+ vmw_resource_unreference(&res);
+ return -ENOMEM;
+ }
- kfree(vmw_bo);
+ cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DEFINE);
+ cmd->header.size = cpu_to_le32(sizeof(cmd->body));
+ cmd->body.cid = cpu_to_le32(res->id);
+
+ vmw_fifo_commit(dev_priv, sizeof(*cmd));
+ (void) vmw_3d_resource_inc(dev_priv, false);
+ vmw_resource_activate(res, vmw_hw_context_destroy);
+ return 0;
+
+out_early:
+ if (res_free == NULL)
+ kfree(res);
+ else
+ res_free(res);
+ return ret;
}
-int vmw_dmabuf_init(struct vmw_private *dev_priv,
- struct vmw_dma_buffer *vmw_bo,
- size_t size, struct ttm_placement *placement,
- bool interruptible,
- void (*bo_free) (struct ttm_buffer_object *bo))
+struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv)
{
- struct ttm_bo_device *bdev = &dev_priv->bdev;
- size_t acc_size;
+ struct vmw_resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
int ret;
- BUG_ON(!bo_free);
-
- acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct vmw_dma_buffer));
- memset(vmw_bo, 0, sizeof(*vmw_bo));
-
- INIT_LIST_HEAD(&vmw_bo->res_list);
+ if (unlikely(res == NULL))
+ return NULL;
- ret = ttm_bo_init(bdev, &vmw_bo->base, size,
- ttm_bo_type_device, placement,
- 0, interruptible,
- NULL, acc_size, NULL, bo_free);
- return ret;
+ ret = vmw_context_init(dev_priv, res, NULL);
+ return (ret == 0) ? res : NULL;
}
-static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo)
+/**
+ * User-space context management:
+ */
+
+static void vmw_user_context_free(struct vmw_resource *res)
{
- struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
+ struct vmw_user_context *ctx =
+ container_of(res, struct vmw_user_context, res);
+ struct vmw_private *dev_priv = res->dev_priv;
- ttm_base_object_kfree(vmw_user_bo, base);
+ ttm_base_object_kfree(ctx, base);
+ ttm_mem_global_free(vmw_mem_glob(dev_priv),
+ vmw_user_context_size);
}
-static void vmw_user_dmabuf_release(struct ttm_base_object **p_base)
+/**
+ * This function is called when user space has no more references on the
+ * base object. It releases the base-object's reference on the resource object.
+ */
+
+static void vmw_user_context_base_release(struct ttm_base_object **p_base)
{
- struct vmw_user_dma_buffer *vmw_user_bo;
struct ttm_base_object *base = *p_base;
- struct ttm_buffer_object *bo;
+ struct vmw_user_context *ctx =
+ container_of(base, struct vmw_user_context, base);
+ struct vmw_resource *res = &ctx->res;
*p_base = NULL;
+ vmw_resource_unreference(&res);
+}
- if (unlikely(base == NULL))
- return;
+int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct vmw_private *dev_priv = vmw_priv(dev);
+ struct vmw_resource *res;
+ struct vmw_user_context *ctx;
+ struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
+ struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+ int ret = 0;
- vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, base);
- bo = &vmw_user_bo->dma.base;
- ttm_bo_unref(&bo);
+ res = vmw_resource_lookup(dev_priv, &dev_priv->context_idr, arg->cid);
+ if (unlikely(res == NULL))
+ return -EINVAL;
+
+ if (res->res_free != &vmw_user_context_free) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ctx = container_of(res, struct vmw_user_context, res);
+ if (ctx->base.tfile != tfile && !ctx->base.shareable) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ ttm_ref_object_base_unref(tfile, ctx->base.hash.key, TTM_REF_USAGE);
+out:
+ vmw_resource_unreference(&res);
+ return ret;
}
-/**
- * vmw_user_dmabuf_alloc - Allocate a user dma buffer
- *
- * @dev_priv: Pointer to a struct device private.
- * @tfile: Pointer to a struct ttm_object_file on which to register the user
- * object.
- * @size: Size of the dma buffer.
- * @shareable: Boolean whether the buffer is shareable with other open files.
- * @handle: Pointer to where the handle value should be assigned.
- * @p_dma_buf: Pointer to where the refcounted struct vmw_dma_buffer pointer
- * should be assigned.
- */
-int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
- struct ttm_object_file *tfile,
- uint32_t size,
- bool shareable,
- uint32_t *handle,
- struct vmw_dma_buffer **p_dma_buf)
+int vmw_context_define_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct vmw_user_dma_buffer *user_bo;
- struct ttm_buffer_object *tmp;
+ struct vmw_private *dev_priv = vmw_priv(dev);
+ struct vmw_user_context *ctx;
+ struct vmw_resource *res;
+ struct vmw_resource *tmp;
+ struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
+ struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
int ret;
- user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL);
- if (unlikely(user_bo == NULL)) {
- DRM_ERROR("Failed to allocate a buffer.\n");
- return -ENOMEM;
- }
- ret = vmw_dmabuf_init(dev_priv, &user_bo->dma, size,
- &vmw_vram_sys_placement, true,
- &vmw_user_dmabuf_destroy);
+ /*
+ * Approximate idr memory usage with 128 bytes. It will be limited
+ * by maximum number_of contexts anyway.
+ */
+
+ if (unlikely(vmw_user_context_size == 0))
+ vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128;
+
+ ret = ttm_read_lock(&vmaster->lock, true);
if (unlikely(ret != 0))
return ret;
- tmp = ttm_bo_reference(&user_bo->dma.base);
- ret = ttm_base_object_init(tfile,
- &user_bo->base,
- shareable,
- ttm_buffer_type,
- &vmw_user_dmabuf_release, NULL);
+ ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
+ vmw_user_context_size,
+ false, true);
if (unlikely(ret != 0)) {
- ttm_bo_unref(&tmp);
- goto out_no_base_object;
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("Out of graphics memory for context"
+ " creation.\n");
+ goto out_unlock;
+ }
+
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (unlikely(ctx == NULL)) {
+ ttm_mem_global_free(vmw_mem_glob(dev_priv),
+ vmw_user_context_size);
+ ret = -ENOMEM;
+ goto out_unlock;
}
- *p_dma_buf = &user_bo->dma;
- *handle = user_bo->base.hash.key;
+ res = &ctx->res;
+ ctx->base.shareable = false;
+ ctx->base.tfile = NULL;
+
+ /*
+ * From here on, the destructor takes over resource freeing.
+ */
+
+ ret = vmw_context_init(dev_priv, res, vmw_user_context_free);
+ if (unlikely(ret != 0))
+ goto out_unlock;
+
+ tmp = vmw_resource_reference(&ctx->res);
+ ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT,
+ &vmw_user_context_base_release, NULL);
+
+ if (unlikely(ret != 0)) {
+ vmw_resource_unreference(&tmp);
+ goto out_err;
+ }
+
+ arg->cid = res->id;
+out_err:
+ vmw_resource_unreference(&res);
+out_unlock:
+ ttm_read_unlock(&vmaster->lock);
+ return ret;
+
+}
+
+int vmw_context_check(struct vmw_private *dev_priv,
+ struct ttm_object_file *tfile,
+ int id,
+ struct vmw_resource **p_res)
+{
+ struct vmw_resource *res;
+ int ret = 0;
+
+ read_lock(&dev_priv->resource_lock);
+ res = idr_find(&dev_priv->context_idr, id);
+ if (res && res->avail) {
+ struct vmw_user_context *ctx =
+ container_of(res, struct vmw_user_context, res);
+ if (ctx->base.tfile != tfile && !ctx->base.shareable)
+ ret = -EPERM;
+ if (p_res)
+ *p_res = vmw_resource_reference(res);
+ } else
+ ret = -EINVAL;
+ read_unlock(&dev_priv->resource_lock);
-out_no_base_object:
return ret;
}
+struct vmw_bpp {
+ uint8_t bpp;
+ uint8_t s_bpp;
+};
+
+/*
+ * Size table for the supported SVGA3D surface formats. It consists of
+ * two values. The bpp value and the s_bpp value which is short for
+ * "stride bits per pixel" The values are given in such a way that the
+ * minimum stride for the image is calculated using
+ *
+ * min_stride = w*s_bpp
+ *
+ * and the total memory requirement for the image is
+ *
+ * h*min_stride*bpp/s_bpp
+ *
+ */
+static const struct vmw_bpp vmw_sf_bpp[] = {
+ [SVGA3D_FORMAT_INVALID] = {0, 0},
+ [SVGA3D_X8R8G8B8] = {32, 32},
+ [SVGA3D_A8R8G8B8] = {32, 32},
+ [SVGA3D_R5G6B5] = {16, 16},
+ [SVGA3D_X1R5G5B5] = {16, 16},
+ [SVGA3D_A1R5G5B5] = {16, 16},
+ [SVGA3D_A4R4G4B4] = {16, 16},
+ [SVGA3D_Z_D32] = {32, 32},
+ [SVGA3D_Z_D16] = {16, 16},
+ [SVGA3D_Z_D24S8] = {32, 32},
+ [SVGA3D_Z_D15S1] = {16, 16},
+ [SVGA3D_LUMINANCE8] = {8, 8},
+ [SVGA3D_LUMINANCE4_ALPHA4] = {8, 8},
+ [SVGA3D_LUMINANCE16] = {16, 16},
+ [SVGA3D_LUMINANCE8_ALPHA8] = {16, 16},
+ [SVGA3D_DXT1] = {4, 16},
+ [SVGA3D_DXT2] = {8, 32},
+ [SVGA3D_DXT3] = {8, 32},
+ [SVGA3D_DXT4] = {8, 32},
+ [SVGA3D_DXT5] = {8, 32},
+ [SVGA3D_BUMPU8V8] = {16, 16},
+ [SVGA3D_BUMPL6V5U5] = {16, 16},
+ [SVGA3D_BUMPX8L8V8U8] = {32, 32},
+ [SVGA3D_ARGB_S10E5] = {16, 16},
+ [SVGA3D_ARGB_S23E8] = {32, 32},
+ [SVGA3D_A2R10G10B10] = {32, 32},
+ [SVGA3D_V8U8] = {16, 16},
+ [SVGA3D_Q8W8V8U8] = {32, 32},
+ [SVGA3D_CxV8U8] = {16, 16},
+ [SVGA3D_X8L8V8U8] = {32, 32},
+ [SVGA3D_A2W10V10U10] = {32, 32},
+ [SVGA3D_ALPHA8] = {8, 8},
+ [SVGA3D_R_S10E5] = {16, 16},
+ [SVGA3D_R_S23E8] = {32, 32},
+ [SVGA3D_RG_S10E5] = {16, 16},
+ [SVGA3D_RG_S23E8] = {32, 32},
+ [SVGA3D_BUFFER] = {8, 8},
+ [SVGA3D_Z_D24X8] = {32, 32},
+ [SVGA3D_V16U16] = {32, 32},
+ [SVGA3D_G16R16] = {32, 32},
+ [SVGA3D_A16B16G16R16] = {64, 64},
+ [SVGA3D_UYVY] = {12, 12},
+ [SVGA3D_YUY2] = {12, 12},
+ [SVGA3D_NV12] = {12, 8},
+ [SVGA3D_AYUV] = {32, 32},
+ [SVGA3D_BC4_UNORM] = {4, 16},
+ [SVGA3D_BC5_UNORM] = {8, 32},
+ [SVGA3D_Z_DF16] = {16, 16},
+ [SVGA3D_Z_DF24] = {24, 24},
+ [SVGA3D_Z_D24S8_INT] = {32, 32}
+};
+
+
+/**
+ * Surface management.
+ */
+
+struct vmw_surface_dma {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdSurfaceDMA body;
+ SVGA3dCopyBox cb;
+ SVGA3dCmdSurfaceDMASuffix suffix;
+};
+
+struct vmw_surface_define {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdDefineSurface body;
+};
+
+struct vmw_surface_destroy {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdDestroySurface body;
+};
+
+
/**
- * vmw_user_dmabuf_verify_access - verify access permissions on this
- * buffer object.
+ * vmw_surface_dma_size - Compute fifo size for a dma command.
+ *
+ * @srf: Pointer to a struct vmw_surface
*
- * @bo: Pointer to the buffer object being accessed
- * @tfile: Identifying the caller.
+ * Computes the required size for a surface dma command for backup or
+ * restoration of the surface represented by @srf.
*/
-int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo,
- struct ttm_object_file *tfile)
+static inline uint32_t vmw_surface_dma_size(const struct vmw_surface *srf)
{
- struct vmw_user_dma_buffer *vmw_user_bo;
+ return srf->num_sizes * sizeof(struct vmw_surface_dma);
+}
- if (unlikely(bo->destroy != vmw_user_dmabuf_destroy))
- return -EPERM;
- vmw_user_bo = vmw_user_dma_buffer(bo);
- return (vmw_user_bo->base.tfile == tfile ||
- vmw_user_bo->base.shareable) ? 0 : -EPERM;
+/**
+ * vmw_surface_define_size - Compute fifo size for a surface define command.
+ *
+ * @srf: Pointer to a struct vmw_surface
+ *
+ * Computes the required size for a surface define command for the definition
+ * of the surface represented by @srf.
+ */
+static inline uint32_t vmw_surface_define_size(const struct vmw_surface *srf)
+{
+ return sizeof(struct vmw_surface_define) + srf->num_sizes *
+ sizeof(SVGA3dSize);
}
-int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+
+/**
+ * vmw_surface_destroy_size - Compute fifo size for a surface destroy command.
+ *
+ * Computes the required size for a surface destroy command for the destruction
+ * of a hw surface.
+ */
+static inline uint32_t vmw_surface_destroy_size(void)
{
- struct vmw_private *dev_priv = vmw_priv(dev);
- union drm_vmw_alloc_dmabuf_arg *arg =
- (union drm_vmw_alloc_dmabuf_arg *)data;
- struct drm_vmw_alloc_dmabuf_req *req = &arg->req;
- struct drm_vmw_dmabuf_rep *rep = &arg->rep;
- struct vmw_dma_buffer *dma_buf;
- uint32_t handle;
- struct vmw_master *vmaster = vmw_master(file_priv->master);
- int ret;
+ return sizeof(struct vmw_surface_destroy);
+}
- ret = ttm_read_lock(&vmaster->lock, true);
- if (unlikely(ret != 0))
- return ret;
+/**
+ * vmw_surface_destroy_encode - Encode a surface_destroy command.
+ *
+ * @id: The surface id
+ * @cmd_space: Pointer to memory area in which the commands should be encoded.
+ */
+static void vmw_surface_destroy_encode(uint32_t id,
+ void *cmd_space)
+{
+ struct vmw_surface_destroy *cmd = (struct vmw_surface_destroy *)
+ cmd_space;
- ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile,
- req->size, false, &handle, &dma_buf);
- if (unlikely(ret != 0))
- goto out_no_dmabuf;
+ cmd->header.id = SVGA_3D_CMD_SURFACE_DESTROY;
+ cmd->header.size = sizeof(cmd->body);
+ cmd->body.sid = id;
+}
+
+/**
+ * vmw_surface_define_encode - Encode a surface_define command.
+ *
+ * @srf: Pointer to a struct vmw_surface object.
+ * @cmd_space: Pointer to memory area in which the commands should be encoded.
+ */
+static void vmw_surface_define_encode(const struct vmw_surface *srf,
+ void *cmd_space)
+{
+ struct vmw_surface_define *cmd = (struct vmw_surface_define *)
+ cmd_space;
+ struct drm_vmw_size *src_size;
+ SVGA3dSize *cmd_size;
+ uint32_t cmd_len;
+ int i;
+
+ cmd_len = sizeof(cmd->body) + srf->num_sizes * sizeof(SVGA3dSize);
+
+ cmd->header.id = SVGA_3D_CMD_SURFACE_DEFINE;
+ cmd->header.size = cmd_len;
+ cmd->body.sid = srf->res.id;
+ cmd->body.surfaceFlags = srf->flags;
+ cmd->body.format = cpu_to_le32(srf->format);
+ for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
+ cmd->body.face[i].numMipLevels = srf->mip_levels[i];
+
+ cmd += 1;
+ cmd_size = (SVGA3dSize *) cmd;
+ src_size = srf->sizes;
+
+ for (i = 0; i < srf->num_sizes; ++i, cmd_size++, src_size++) {
+ cmd_size->width = src_size->width;
+ cmd_size->height = src_size->height;
+ cmd_size->depth = src_size->depth;
+ }
+}
+
+
+/**
+ * vmw_surface_dma_encode - Encode a surface_dma command.
+ *
+ * @srf: Pointer to a struct vmw_surface object.
+ * @cmd_space: Pointer to memory area in which the commands should be encoded.
+ * @ptr: Pointer to an SVGAGuestPtr indicating where the surface contents
+ * should be placed or read from.
+ * @to_surface: Boolean whether to DMA to the surface or from the surface.
+ */
+static void vmw_surface_dma_encode(struct vmw_surface *srf,
+ void *cmd_space,
+ const SVGAGuestPtr *ptr,
+ bool to_surface)
+{
+ uint32_t i;
+ uint32_t bpp = vmw_sf_bpp[srf->format].bpp;
+ uint32_t stride_bpp = vmw_sf_bpp[srf->format].s_bpp;
+ struct vmw_surface_dma *cmd = (struct vmw_surface_dma *)cmd_space;
+
+ for (i = 0; i < srf->num_sizes; ++i) {
+ SVGA3dCmdHeader *header = &cmd->header;
+ SVGA3dCmdSurfaceDMA *body = &cmd->body;
+ SVGA3dCopyBox *cb = &cmd->cb;
+ SVGA3dCmdSurfaceDMASuffix *suffix = &cmd->suffix;
+ const struct vmw_surface_offset *cur_offset = &srf->offsets[i];
+ const struct drm_vmw_size *cur_size = &srf->sizes[i];
+
+ header->id = SVGA_3D_CMD_SURFACE_DMA;
+ header->size = sizeof(*body) + sizeof(*cb) + sizeof(*suffix);
+
+ body->guest.ptr = *ptr;
+ body->guest.ptr.offset += cur_offset->bo_offset;
+ body->guest.pitch = (cur_size->width * stride_bpp + 7) >> 3;
+ body->host.sid = srf->res.id;
+ body->host.face = cur_offset->face;
+ body->host.mipmap = cur_offset->mip;
+ body->transfer = ((to_surface) ? SVGA3D_WRITE_HOST_VRAM :
+ SVGA3D_READ_HOST_VRAM);
+ cb->x = 0;
+ cb->y = 0;
+ cb->z = 0;
+ cb->srcx = 0;
+ cb->srcy = 0;
+ cb->srcz = 0;
+ cb->w = cur_size->width;
+ cb->h = cur_size->height;
+ cb->d = cur_size->depth;
+
+ suffix->suffixSize = sizeof(*suffix);
+ suffix->maximumOffset = body->guest.pitch*cur_size->height*
+ cur_size->depth*bpp / stride_bpp;
+ suffix->flags.discard = 0;
+ suffix->flags.unsynchronized = 0;
+ suffix->flags.reserved = 0;
+ ++cmd;
+ }
+};
+
+
+static void vmw_hw_surface_destroy(struct vmw_resource *res)
+{
+
+ struct vmw_private *dev_priv = res->dev_priv;
+ struct vmw_surface *srf;
+ void *cmd;
+
+ if (res->id != -1) {
+
+ cmd = vmw_fifo_reserve(dev_priv, vmw_surface_destroy_size());
+ if (unlikely(cmd == NULL)) {
+ DRM_ERROR("Failed reserving FIFO space for surface "
+ "destruction.\n");
+ return;
+ }
+
+ vmw_surface_destroy_encode(res->id, cmd);
+ vmw_fifo_commit(dev_priv, vmw_surface_destroy_size());
+
+ /*
+ * used_memory_size_atomic, or separate lock
+ * to avoid taking dev_priv::cmdbuf_mutex in
+ * the destroy path.
+ */
+
+ mutex_lock(&dev_priv->cmdbuf_mutex);
+ srf = container_of(res, struct vmw_surface, res);
+ dev_priv->used_memory_size -= srf->backup_size;
+ mutex_unlock(&dev_priv->cmdbuf_mutex);
+
+ }
+ vmw_3d_resource_dec(dev_priv, false);
+}
+
+void vmw_surface_res_free(struct vmw_resource *res)
+{
+ struct vmw_surface *srf = container_of(res, struct vmw_surface, res);
+
+ if (srf->backup)
+ ttm_bo_unref(&srf->backup);
+ kfree(srf->offsets);
+ kfree(srf->sizes);
+ kfree(srf->snooper.image);
+ kfree(srf);
+}
+
+
+/**
+ * vmw_surface_do_validate - make a surface available to the device.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @srf: Pointer to a struct vmw_surface.
+ *
+ * If the surface doesn't have a hw id, allocate one, and optionally
+ * DMA the backed up surface contents to the device.
+ *
+ * Returns -EBUSY if there wasn't sufficient device resources to
+ * complete the validation. Retry after freeing up resources.
+ *
+ * May return other errors if the kernel is out of guest resources.
+ */
+int vmw_surface_do_validate(struct vmw_private *dev_priv,
+ struct vmw_surface *srf)
+{
+ struct vmw_resource *res = &srf->res;
+ struct list_head val_list;
+ struct ttm_validate_buffer val_buf;
+ uint32_t submit_size;
+ uint8_t *cmd;
+ int ret;
+
+ if (likely(res->id != -1))
+ return 0;
+
+ if (unlikely(dev_priv->used_memory_size + srf->backup_size >=
+ dev_priv->memory_size))
+ return -EBUSY;
+
+ /*
+ * Reserve- and validate the backup DMA bo.
+ */
+
+ if (srf->backup) {
+ INIT_LIST_HEAD(&val_list);
+ val_buf.bo = ttm_bo_reference(srf->backup);
+ list_add_tail(&val_buf.head, &val_list);
+ ret = ttm_eu_reserve_buffers(&val_list);
+ if (unlikely(ret != 0))
+ goto out_no_reserve;
+
+ ret = ttm_bo_validate(srf->backup, &vmw_srf_placement,
+ true, false, false);
+ if (unlikely(ret != 0))
+ goto out_no_validate;
+ }
+
+ /*
+ * Alloc id for the resource.
+ */
+
+ ret = vmw_resource_alloc_id(dev_priv, res);
+ if (unlikely(ret != 0)) {
+ DRM_ERROR("Failed to allocate a surface id.\n");
+ goto out_no_id;
+ }
+ if (unlikely(res->id >= SVGA3D_MAX_SURFACE_IDS)) {
+ ret = -EBUSY;
+ goto out_no_fifo;
+ }
+
+
+ /*
+ * Encode surface define- and dma commands.
+ */
+
+ submit_size = vmw_surface_define_size(srf);
+ if (srf->backup)
+ submit_size += vmw_surface_dma_size(srf);
+
+ cmd = vmw_fifo_reserve(dev_priv, submit_size);
+ if (unlikely(cmd == NULL)) {
+ DRM_ERROR("Failed reserving FIFO space for surface "
+ "validation.\n");
+ ret = -ENOMEM;
+ goto out_no_fifo;
+ }
+
+ vmw_surface_define_encode(srf, cmd);
+ if (srf->backup) {
+ SVGAGuestPtr ptr;
+
+ cmd += vmw_surface_define_size(srf);
+ vmw_bo_get_guest_ptr(srf->backup, &ptr);
+ vmw_surface_dma_encode(srf, cmd, &ptr, true);
+ }
+
+ vmw_fifo_commit(dev_priv, submit_size);
+
+ /*
+ * Create a fence object and fence the backup buffer.
+ */
+
+ if (srf->backup) {
+ struct vmw_fence_obj *fence;
+
+ (void) vmw_execbuf_fence_commands(NULL, dev_priv,
+ &fence, NULL);
+ ttm_eu_fence_buffer_objects(&val_list, fence);
+ if (likely(fence != NULL))
+ vmw_fence_obj_unreference(&fence);
+ ttm_bo_unref(&val_buf.bo);
+ ttm_bo_unref(&srf->backup);
+ }
+
+ /*
+ * Surface memory usage accounting.
+ */
+
+ dev_priv->used_memory_size += srf->backup_size;
+
+ return 0;
+
+out_no_fifo:
+ vmw_resource_release_id(res);
+out_no_id:
+out_no_validate:
+ if (srf->backup)
+ ttm_eu_backoff_reservation(&val_list);
+out_no_reserve:
+ if (srf->backup)
+ ttm_bo_unref(&val_buf.bo);
+ return ret;
+}
+
+/**
+ * vmw_surface_evict - Evict a hw surface.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @srf: Pointer to a struct vmw_surface
+ *
+ * DMA the contents of a hw surface to a backup guest buffer object,
+ * and destroy the hw surface, releasing its id.
+ */
+int vmw_surface_evict(struct vmw_private *dev_priv,
+ struct vmw_surface *srf)
+{
+ struct vmw_resource *res = &srf->res;
+ struct list_head val_list;
+ struct ttm_validate_buffer val_buf;
+ uint32_t submit_size;
+ uint8_t *cmd;
+ int ret;
+ struct vmw_fence_obj *fence;
+ SVGAGuestPtr ptr;
+
+ BUG_ON(res->id == -1);
+
+ /*
+ * Create a surface backup buffer object.
+ */
+
+ if (!srf->backup) {
+ ret = ttm_bo_create(&dev_priv->bdev, srf->backup_size,
+ ttm_bo_type_device,
+ &vmw_srf_placement, 0, true,
+ NULL, &srf->backup);
+ if (unlikely(ret != 0))
+ return ret;
+ }
+
+ /*
+ * Reserve- and validate the backup DMA bo.
+ */
+
+ INIT_LIST_HEAD(&val_list);
+ val_buf.bo = ttm_bo_reference(srf->backup);
+ list_add_tail(&val_buf.head, &val_list);
+ ret = ttm_eu_reserve_buffers(&val_list);
+ if (unlikely(ret != 0))
+ goto out_no_reserve;
+
+ ret = ttm_bo_validate(srf->backup, &vmw_srf_placement,
+ true, false, false);
+ if (unlikely(ret != 0))
+ goto out_no_validate;
- rep->handle = handle;
- rep->map_handle = dma_buf->base.addr_space_offset;
- rep->cur_gmr_id = handle;
- rep->cur_gmr_offset = 0;
- vmw_dmabuf_unreference(&dma_buf);
+ /*
+ * Encode the dma- and surface destroy commands.
+ */
+
+ submit_size = vmw_surface_dma_size(srf) + vmw_surface_destroy_size();
+ cmd = vmw_fifo_reserve(dev_priv, submit_size);
+ if (unlikely(cmd == NULL)) {
+ DRM_ERROR("Failed reserving FIFO space for surface "
+ "eviction.\n");
+ ret = -ENOMEM;
+ goto out_no_fifo;
+ }
+
+ vmw_bo_get_guest_ptr(srf->backup, &ptr);
+ vmw_surface_dma_encode(srf, cmd, &ptr, false);
+ cmd += vmw_surface_dma_size(srf);
+ vmw_surface_destroy_encode(res->id, cmd);
+ vmw_fifo_commit(dev_priv, submit_size);
+
+ /*
+ * Surface memory usage accounting.
+ */
+
+ dev_priv->used_memory_size -= srf->backup_size;
+
+ /*
+ * Create a fence object and fence the DMA buffer.
+ */
+
+ (void) vmw_execbuf_fence_commands(NULL, dev_priv,
+ &fence, NULL);
+ ttm_eu_fence_buffer_objects(&val_list, fence);
+ if (likely(fence != NULL))
+ vmw_fence_obj_unreference(&fence);
+ ttm_bo_unref(&val_buf.bo);
+
+ /*
+ * Release the surface ID.
+ */
+
+ vmw_resource_release_id(res);
+
+ return 0;
+
+out_no_fifo:
+out_no_validate:
+ if (srf->backup)
+ ttm_eu_backoff_reservation(&val_list);
+out_no_reserve:
+ ttm_bo_unref(&val_buf.bo);
+ ttm_bo_unref(&srf->backup);
+ return ret;
+}
+
+
+/**
+ * vmw_surface_validate - make a surface available to the device, evicting
+ * other surfaces if needed.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @srf: Pointer to a struct vmw_surface.
+ *
+ * Try to validate a surface and if it fails due to limited device resources,
+ * repeatedly try to evict other surfaces until the request can be
+ * acommodated.
+ *
+ * May return errors if out of resources.
+ */
+int vmw_surface_validate(struct vmw_private *dev_priv,
+ struct vmw_surface *srf)
+{
+ int ret;
+ struct vmw_surface *evict_srf;
+
+ do {
+ write_lock(&dev_priv->resource_lock);
+ list_del_init(&srf->lru_head);
+ write_unlock(&dev_priv->resource_lock);
+
+ ret = vmw_surface_do_validate(dev_priv, srf);
+ if (likely(ret != -EBUSY))
+ break;
+
+ write_lock(&dev_priv->resource_lock);
+ if (list_empty(&dev_priv->surface_lru)) {
+ DRM_ERROR("Out of device memory for surfaces.\n");
+ ret = -EBUSY;
+ write_unlock(&dev_priv->resource_lock);
+ break;
+ }
+
+ evict_srf = vmw_surface_reference
+ (list_first_entry(&dev_priv->surface_lru,
+ struct vmw_surface,
+ lru_head));
+ list_del_init(&evict_srf->lru_head);
+
+ write_unlock(&dev_priv->resource_lock);
+ (void) vmw_surface_evict(dev_priv, evict_srf);
+
+ vmw_surface_unreference(&evict_srf);
+
+ } while (1);
+
+ if (unlikely(ret != 0 && srf->res.id != -1)) {
+ write_lock(&dev_priv->resource_lock);
+ list_add_tail(&srf->lru_head, &dev_priv->surface_lru);
+ write_unlock(&dev_priv->resource_lock);
+ }
+
+ return ret;
+}
+
+
+/**
+ * vmw_surface_remove_from_lists - Remove surface resources from lookup lists
+ *
+ * @res: Pointer to a struct vmw_resource embedded in a struct vmw_surface
+ *
+ * As part of the resource destruction, remove the surface from any
+ * lookup lists.
+ */
+static void vmw_surface_remove_from_lists(struct vmw_resource *res)
+{
+ struct vmw_surface *srf = container_of(res, struct vmw_surface, res);
+
+ list_del_init(&srf->lru_head);
+}
+
+int vmw_surface_init(struct vmw_private *dev_priv,
+ struct vmw_surface *srf,
+ void (*res_free) (struct vmw_resource *res))
+{
+ int ret;
+ struct vmw_resource *res = &srf->res;
+
+ BUG_ON(res_free == NULL);
+ INIT_LIST_HEAD(&srf->lru_head);
+ ret = vmw_resource_init(dev_priv, res, &dev_priv->surface_idr,
+ VMW_RES_SURFACE, true, res_free,
+ vmw_surface_remove_from_lists);
+
+ if (unlikely(ret != 0))
+ res_free(res);
+
+ /*
+ * The surface won't be visible to hardware until a
+ * surface validate.
+ */
+
+ (void) vmw_3d_resource_inc(dev_priv, false);
+ vmw_resource_activate(res, vmw_hw_surface_destroy);
+ return ret;
+}
+
+static void vmw_user_surface_free(struct vmw_resource *res)
+{
+ struct vmw_surface *srf = container_of(res, struct vmw_surface, res);
+ struct vmw_user_surface *user_srf =
+ container_of(srf, struct vmw_user_surface, srf);
+ struct vmw_private *dev_priv = srf->res.dev_priv;
+ uint32_t size = user_srf->size;
+
+ if (srf->backup)
+ ttm_bo_unref(&srf->backup);
+ kfree(srf->offsets);
+ kfree(srf->sizes);
+ kfree(srf->snooper.image);
+ ttm_base_object_kfree(user_srf, base);
+ ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
+}
+
+/**
+ * vmw_resource_unreserve - unreserve resources previously reserved for
+ * command submission.
+ *
+ * @list_head: list of resources to unreserve.
+ *
+ * Currently only surfaces are considered, and unreserving a surface
+ * means putting it back on the device's surface lru list,
+ * so that it can be evicted if necessary.
+ * This function traverses the resource list and
+ * checks whether resources are surfaces, and in that case puts them back
+ * on the device's surface LRU list.
+ */
+void vmw_resource_unreserve(struct list_head *list)
+{
+ struct vmw_resource *res;
+ struct vmw_surface *srf;
+ rwlock_t *lock = NULL;
+
+ list_for_each_entry(res, list, validate_head) {
+
+ if (res->res_free != &vmw_surface_res_free &&
+ res->res_free != &vmw_user_surface_free)
+ continue;
+
+ if (unlikely(lock == NULL)) {
+ lock = &res->dev_priv->resource_lock;
+ write_lock(lock);
+ }
+
+ srf = container_of(res, struct vmw_surface, res);
+ list_del_init(&srf->lru_head);
+ list_add_tail(&srf->lru_head, &res->dev_priv->surface_lru);
+ }
+
+ if (lock != NULL)
+ write_unlock(lock);
+}
+
+/**
+ * Helper function that looks either a surface or dmabuf.
+ *
+ * The pointer this pointed at by out_surf and out_buf needs to be null.
+ */
+int vmw_user_lookup_handle(struct vmw_private *dev_priv,
+ struct ttm_object_file *tfile,
+ uint32_t handle,
+ struct vmw_surface **out_surf,
+ struct vmw_dma_buffer **out_buf)
+{
+ int ret;
+
+ BUG_ON(*out_surf || *out_buf);
+
+ ret = vmw_user_surface_lookup_handle(dev_priv, tfile, handle, out_surf);
+ if (!ret)
+ return 0;
+
+ ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf);
+ return ret;
+}
+
+
+int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv,
+ struct ttm_object_file *tfile,
+ uint32_t handle, struct vmw_surface **out)
+{
+ struct vmw_resource *res;
+ struct vmw_surface *srf;
+ struct vmw_user_surface *user_srf;
+ struct ttm_base_object *base;
+ int ret = -EINVAL;
+
+ base = ttm_base_object_lookup(tfile, handle);
+ if (unlikely(base == NULL))
+ return -EINVAL;
+
+ if (unlikely(base->object_type != VMW_RES_SURFACE))
+ goto out_bad_resource;
+
+ user_srf = container_of(base, struct vmw_user_surface, base);
+ srf = &user_srf->srf;
+ res = &srf->res;
+
+ read_lock(&dev_priv->resource_lock);
+
+ if (!res->avail || res->res_free != &vmw_user_surface_free) {
+ read_unlock(&dev_priv->resource_lock);
+ goto out_bad_resource;
+ }
+
+ kref_get(&res->kref);
+ read_unlock(&dev_priv->resource_lock);
+
+ *out = srf;
+ ret = 0;
+
+out_bad_resource:
+ ttm_base_object_unref(&base);
+
+ return ret;
+}
+
+static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
+{
+ struct ttm_base_object *base = *p_base;
+ struct vmw_user_surface *user_srf =
+ container_of(base, struct vmw_user_surface, base);
+ struct vmw_resource *res = &user_srf->srf.res;
+
+ *p_base = NULL;
+ vmw_resource_unreference(&res);
+}
+
+int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data;
+ struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+
+ return ttm_ref_object_base_unref(tfile, arg->sid, TTM_REF_USAGE);
+}
+
+int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct vmw_private *dev_priv = vmw_priv(dev);
+ struct vmw_user_surface *user_srf;
+ struct vmw_surface *srf;
+ struct vmw_resource *res;
+ struct vmw_resource *tmp;
+ union drm_vmw_surface_create_arg *arg =
+ (union drm_vmw_surface_create_arg *)data;
+ struct drm_vmw_surface_create_req *req = &arg->req;
+ struct drm_vmw_surface_arg *rep = &arg->rep;
+ struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+ struct drm_vmw_size __user *user_sizes;
+ int ret;
+ int i, j;
+ uint32_t cur_bo_offset;
+ struct drm_vmw_size *cur_size;
+ struct vmw_surface_offset *cur_offset;
+ uint32_t stride_bpp;
+ uint32_t bpp;
+ uint32_t num_sizes;
+ uint32_t size;
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
+
+ if (unlikely(vmw_user_surface_size == 0))
+ vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
+ 128;
+
+ num_sizes = 0;
+ for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
+ num_sizes += req->mip_levels[i];
+
+ if (num_sizes > DRM_VMW_MAX_SURFACE_FACES *
+ DRM_VMW_MAX_MIP_LEVELS)
+ return -EINVAL;
+
+ size = vmw_user_surface_size + 128 +
+ ttm_round_pot(num_sizes * sizeof(struct drm_vmw_size)) +
+ ttm_round_pot(num_sizes * sizeof(struct vmw_surface_offset));
+
+
+ ret = ttm_read_lock(&vmaster->lock, true);
+ if (unlikely(ret != 0))
+ return ret;
+
+ ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
+ size, false, true);
+ if (unlikely(ret != 0)) {
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("Out of graphics memory for surface"
+ " creation.\n");
+ goto out_unlock;
+ }
+
+ user_srf = kmalloc(sizeof(*user_srf), GFP_KERNEL);
+ if (unlikely(user_srf == NULL)) {
+ ret = -ENOMEM;
+ goto out_no_user_srf;
+ }
+
+ srf = &user_srf->srf;
+ res = &srf->res;
+
+ srf->flags = req->flags;
+ srf->format = req->format;
+ srf->scanout = req->scanout;
+ srf->backup = NULL;
+
+ memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels));
+ srf->num_sizes = num_sizes;
+ user_srf->size = size;
+
+ srf->sizes = kmalloc(srf->num_sizes * sizeof(*srf->sizes), GFP_KERNEL);
+ if (unlikely(srf->sizes == NULL)) {
+ ret = -ENOMEM;
+ goto out_no_sizes;
+ }
+ srf->offsets = kmalloc(srf->num_sizes * sizeof(*srf->offsets),
+ GFP_KERNEL);
+ if (unlikely(srf->sizes == NULL)) {
+ ret = -ENOMEM;
+ goto out_no_offsets;
+ }
+
+ user_sizes = (struct drm_vmw_size __user *)(unsigned long)
+ req->size_addr;
+
+ ret = copy_from_user(srf->sizes, user_sizes,
+ srf->num_sizes * sizeof(*srf->sizes));
+ if (unlikely(ret != 0)) {
+ ret = -EFAULT;
+ goto out_no_copy;
+ }
+
+ cur_bo_offset = 0;
+ cur_offset = srf->offsets;
+ cur_size = srf->sizes;
+
+ bpp = vmw_sf_bpp[srf->format].bpp;
+ stride_bpp = vmw_sf_bpp[srf->format].s_bpp;
+
+ for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
+ for (j = 0; j < srf->mip_levels[i]; ++j) {
+ uint32_t stride =
+ (cur_size->width * stride_bpp + 7) >> 3;
+
+ cur_offset->face = i;
+ cur_offset->mip = j;
+ cur_offset->bo_offset = cur_bo_offset;
+ cur_bo_offset += stride * cur_size->height *
+ cur_size->depth * bpp / stride_bpp;
+ ++cur_offset;
+ ++cur_size;
+ }
+ }
+ srf->backup_size = cur_bo_offset;
+
+ if (srf->scanout &&
+ srf->num_sizes == 1 &&
+ srf->sizes[0].width == 64 &&
+ srf->sizes[0].height == 64 &&
+ srf->format == SVGA3D_A8R8G8B8) {
+
+ /* allocate image area and clear it */
+ srf->snooper.image = kzalloc(64 * 64 * 4, GFP_KERNEL);
+ if (!srf->snooper.image) {
+ DRM_ERROR("Failed to allocate cursor_image\n");
+ ret = -ENOMEM;
+ goto out_no_copy;
+ }
+ } else {
+ srf->snooper.image = NULL;
+ }
+ srf->snooper.crtc = NULL;
+
+ user_srf->base.shareable = false;
+ user_srf->base.tfile = NULL;
+
+ /**
+ * From this point, the generic resource management functions
+ * destroy the object on failure.
+ */
+
+ ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free);
+ if (unlikely(ret != 0))
+ goto out_unlock;
+
+ tmp = vmw_resource_reference(&srf->res);
+ ret = ttm_base_object_init(tfile, &user_srf->base,
+ req->shareable, VMW_RES_SURFACE,
+ &vmw_user_surface_base_release, NULL);
+
+ if (unlikely(ret != 0)) {
+ vmw_resource_unreference(&tmp);
+ vmw_resource_unreference(&res);
+ goto out_unlock;
+ }
+
+ rep->sid = user_srf->base.hash.key;
+ if (rep->sid == SVGA3D_INVALID_ID)
+ DRM_ERROR("Created bad Surface ID.\n");
+
+ vmw_resource_unreference(&res);
+
+ ttm_read_unlock(&vmaster->lock);
+ return 0;
+out_no_copy:
+ kfree(srf->offsets);
+out_no_offsets:
+ kfree(srf->sizes);
+out_no_sizes:
+ kfree(user_srf);
+out_no_user_srf:
+ ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
+out_unlock:
+ ttm_read_unlock(&vmaster->lock);
+ return ret;
+}
+
+int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ union drm_vmw_surface_reference_arg *arg =
+ (union drm_vmw_surface_reference_arg *)data;
+ struct drm_vmw_surface_arg *req = &arg->req;
+ struct drm_vmw_surface_create_req *rep = &arg->rep;
+ struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+ struct vmw_surface *srf;
+ struct vmw_user_surface *user_srf;
+ struct drm_vmw_size __user *user_sizes;
+ struct ttm_base_object *base;
+ int ret = -EINVAL;
+
+ base = ttm_base_object_lookup(tfile, req->sid);
+ if (unlikely(base == NULL)) {
+ DRM_ERROR("Could not find surface to reference.\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(base->object_type != VMW_RES_SURFACE))
+ goto out_bad_resource;
+
+ user_srf = container_of(base, struct vmw_user_surface, base);
+ srf = &user_srf->srf;
+
+ ret = ttm_ref_object_add(tfile, &user_srf->base, TTM_REF_USAGE, NULL);
+ if (unlikely(ret != 0)) {
+ DRM_ERROR("Could not add a reference to a surface.\n");
+ goto out_no_reference;
+ }
+
+ rep->flags = srf->flags;
+ rep->format = srf->format;
+ memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels));
+ user_sizes = (struct drm_vmw_size __user *)(unsigned long)
+ rep->size_addr;
+
+ if (user_sizes)
+ ret = copy_to_user(user_sizes, srf->sizes,
+ srf->num_sizes * sizeof(*srf->sizes));
+ if (unlikely(ret != 0)) {
+ DRM_ERROR("copy_to_user failed %p %u\n",
+ user_sizes, srf->num_sizes);
+ ret = -EFAULT;
+ }
+out_bad_resource:
+out_no_reference:
+ ttm_base_object_unref(&base);
+
+ return ret;
+}
+
+int vmw_surface_check(struct vmw_private *dev_priv,
+ struct ttm_object_file *tfile,
+ uint32_t handle, int *id)
+{
+ struct ttm_base_object *base;
+ struct vmw_user_surface *user_srf;
+
+ int ret = -EPERM;
+
+ base = ttm_base_object_lookup(tfile, handle);
+ if (unlikely(base == NULL))
+ return -EINVAL;
+
+ if (unlikely(base->object_type != VMW_RES_SURFACE))
+ goto out_bad_surface;
+
+ user_srf = container_of(base, struct vmw_user_surface, base);
+ *id = user_srf->srf.res.id;
+ ret = 0;
+
+out_bad_surface:
+ /**
+ * FIXME: May deadlock here when called from the
+ * command parsing code.
+ */
+
+ ttm_base_object_unref(&base);
+ return ret;
+}
+
+/**
+ * Buffer management.
+ */
+void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
+{
+ struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
+
+ kfree(vmw_bo);
+}
+
+int vmw_dmabuf_init(struct vmw_private *dev_priv,
+ struct vmw_dma_buffer *vmw_bo,
+ size_t size, struct ttm_placement *placement,
+ bool interruptible,
+ void (*bo_free) (struct ttm_buffer_object *bo))
+{
+ struct ttm_bo_device *bdev = &dev_priv->bdev;
+ size_t acc_size;
+ int ret;
+
+ BUG_ON(!bo_free);
+
+ acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct vmw_dma_buffer));
+ memset(vmw_bo, 0, sizeof(*vmw_bo));
+
+ INIT_LIST_HEAD(&vmw_bo->validate_list);
+
+ ret = ttm_bo_init(bdev, &vmw_bo->base, size,
+ ttm_bo_type_device, placement,
+ 0, interruptible,
+ NULL, acc_size, NULL, bo_free);
+ return ret;
+}
+
+static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo)
+{
+ struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
+
+ ttm_base_object_kfree(vmw_user_bo, base);
+}
+
+static void vmw_user_dmabuf_release(struct ttm_base_object **p_base)
+{
+ struct vmw_user_dma_buffer *vmw_user_bo;
+ struct ttm_base_object *base = *p_base;
+ struct ttm_buffer_object *bo;
+
+ *p_base = NULL;
+
+ if (unlikely(base == NULL))
+ return;
+
+ vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, base);
+ bo = &vmw_user_bo->dma.base;
+ ttm_bo_unref(&bo);
+}
+
+int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct vmw_private *dev_priv = vmw_priv(dev);
+ union drm_vmw_alloc_dmabuf_arg *arg =
+ (union drm_vmw_alloc_dmabuf_arg *)data;
+ struct drm_vmw_alloc_dmabuf_req *req = &arg->req;
+ struct drm_vmw_dmabuf_rep *rep = &arg->rep;
+ struct vmw_user_dma_buffer *vmw_user_bo;
+ struct ttm_buffer_object *tmp;
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
+ int ret;
+
+ vmw_user_bo = kzalloc(sizeof(*vmw_user_bo), GFP_KERNEL);
+ if (unlikely(vmw_user_bo == NULL))
+ return -ENOMEM;
+
+ ret = ttm_read_lock(&vmaster->lock, true);
+ if (unlikely(ret != 0)) {
+ kfree(vmw_user_bo);
+ return ret;
+ }
+
+ ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, req->size,
+ &vmw_vram_sys_placement, true,
+ &vmw_user_dmabuf_destroy);
+ if (unlikely(ret != 0))
+ goto out_no_dmabuf;
+
+ tmp = ttm_bo_reference(&vmw_user_bo->dma.base);
+ ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile,
+ &vmw_user_bo->base,
+ false,
+ ttm_buffer_type,
+ &vmw_user_dmabuf_release, NULL);
+ if (unlikely(ret != 0))
+ goto out_no_base_object;
+ else {
+ rep->handle = vmw_user_bo->base.hash.key;
+ rep->map_handle = vmw_user_bo->dma.base.addr_space_offset;
+ rep->cur_gmr_id = vmw_user_bo->base.hash.key;
+ rep->cur_gmr_offset = 0;
+ }
+out_no_base_object:
+ ttm_bo_unref(&tmp);
out_no_dmabuf:
ttm_read_unlock(&vmaster->lock);
@@ -524,6 +1653,27 @@ int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
TTM_REF_USAGE);
}
+uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
+ uint32_t cur_validate_node)
+{
+ struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
+
+ if (likely(vmw_bo->on_validate_list))
+ return vmw_bo->cur_validate_node;
+
+ vmw_bo->cur_validate_node = cur_validate_node;
+ vmw_bo->on_validate_list = true;
+
+ return cur_validate_node;
+}
+
+void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo)
+{
+ struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
+
+ vmw_bo->on_validate_list = false;
+}
+
int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
uint32_t handle, struct vmw_dma_buffer **out)
{
@@ -552,18 +1702,6 @@ int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
return 0;
}
-int vmw_user_dmabuf_reference(struct ttm_object_file *tfile,
- struct vmw_dma_buffer *dma_buf)
-{
- struct vmw_user_dma_buffer *user_bo;
-
- if (dma_buf->base.destroy != vmw_user_dmabuf_destroy)
- return -EINVAL;
-
- user_bo = container_of(dma_buf, struct vmw_user_dma_buffer, dma);
- return ttm_ref_object_add(tfile, &user_bo->base, TTM_REF_USAGE, NULL);
-}
-
/*
* Stream management
*/
@@ -588,8 +1726,8 @@ static int vmw_stream_init(struct vmw_private *dev_priv,
struct vmw_resource *res = &stream->res;
int ret;
- ret = vmw_resource_init(dev_priv, res, false, res_free,
- &vmw_stream_func);
+ ret = vmw_resource_init(dev_priv, res, &dev_priv->stream_idr,
+ VMW_RES_STREAM, false, res_free, NULL);
if (unlikely(ret != 0)) {
if (res_free == NULL)
@@ -611,6 +1749,10 @@ static int vmw_stream_init(struct vmw_private *dev_priv,
return 0;
}
+/**
+ * User-space context management:
+ */
+
static void vmw_user_stream_free(struct vmw_resource *res)
{
struct vmw_user_stream *stream =
@@ -646,11 +1788,9 @@ int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
struct vmw_user_stream *stream;
struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data;
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
- struct idr *idr = &dev_priv->res_idr[vmw_res_stream];
int ret = 0;
-
- res = vmw_resource_lookup(dev_priv, idr, arg->stream_id);
+ res = vmw_resource_lookup(dev_priv, &dev_priv->stream_idr, arg->stream_id);
if (unlikely(res == NULL))
return -EINVAL;
@@ -751,8 +1891,7 @@ int vmw_user_stream_lookup(struct vmw_private *dev_priv,
struct vmw_resource *res;
int ret;
- res = vmw_resource_lookup(dev_priv, &dev_priv->res_idr[vmw_res_stream],
- *inout_id);
+ res = vmw_resource_lookup(dev_priv, &dev_priv->stream_idr, *inout_id);
if (unlikely(res == NULL))
return -EINVAL;
@@ -847,453 +1986,3 @@ int vmw_dumb_destroy(struct drm_file *file_priv,
return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
handle, TTM_REF_USAGE);
}
-
-/**
- * vmw_resource_buf_alloc - Allocate a backup buffer for a resource.
- *
- * @res: The resource for which to allocate a backup buffer.
- * @interruptible: Whether any sleeps during allocation should be
- * performed while interruptible.
- */
-static int vmw_resource_buf_alloc(struct vmw_resource *res,
- bool interruptible)
-{
- unsigned long size =
- (res->backup_size + PAGE_SIZE - 1) & PAGE_MASK;
- struct vmw_dma_buffer *backup;
- int ret;
-
- if (likely(res->backup)) {
- BUG_ON(res->backup->base.num_pages * PAGE_SIZE < size);
- return 0;
- }
-
- backup = kzalloc(sizeof(*backup), GFP_KERNEL);
- if (unlikely(backup == NULL))
- return -ENOMEM;
-
- ret = vmw_dmabuf_init(res->dev_priv, backup, res->backup_size,
- res->func->backup_placement,
- interruptible,
- &vmw_dmabuf_bo_free);
- if (unlikely(ret != 0))
- goto out_no_dmabuf;
-
- res->backup = backup;
-
-out_no_dmabuf:
- return ret;
-}
-
-/**
- * vmw_resource_do_validate - Make a resource up-to-date and visible
- * to the device.
- *
- * @res: The resource to make visible to the device.
- * @val_buf: Information about a buffer possibly
- * containing backup data if a bind operation is needed.
- *
- * On hardware resource shortage, this function returns -EBUSY and
- * should be retried once resources have been freed up.
- */
-static int vmw_resource_do_validate(struct vmw_resource *res,
- struct ttm_validate_buffer *val_buf)
-{
- int ret = 0;
- const struct vmw_res_func *func = res->func;
-
- if (unlikely(res->id == -1)) {
- ret = func->create(res);
- if (unlikely(ret != 0))
- return ret;
- }
-
- if (func->bind &&
- ((func->needs_backup && list_empty(&res->mob_head) &&
- val_buf->bo != NULL) ||
- (!func->needs_backup && val_buf->bo != NULL))) {
- ret = func->bind(res, val_buf);
- if (unlikely(ret != 0))
- goto out_bind_failed;
- if (func->needs_backup)
- list_add_tail(&res->mob_head, &res->backup->res_list);
- }
-
- /*
- * Only do this on write operations, and move to
- * vmw_resource_unreserve if it can be called after
- * backup buffers have been unreserved. Otherwise
- * sort out locking.
- */
- res->res_dirty = true;
-
- return 0;
-
-out_bind_failed:
- func->destroy(res);
-
- return ret;
-}
-
-/**
- * vmw_resource_unreserve - Unreserve a resource previously reserved for
- * command submission.
- *
- * @res: Pointer to the struct vmw_resource to unreserve.
- * @new_backup: Pointer to new backup buffer if command submission
- * switched.
- * @new_backup_offset: New backup offset if @new_backup is !NULL.
- *
- * Currently unreserving a resource means putting it back on the device's
- * resource lru list, so that it can be evicted if necessary.
- */
-void vmw_resource_unreserve(struct vmw_resource *res,
- struct vmw_dma_buffer *new_backup,
- unsigned long new_backup_offset)
-{
- struct vmw_private *dev_priv = res->dev_priv;
-
- if (!list_empty(&res->lru_head))
- return;
-
- if (new_backup && new_backup != res->backup) {
-
- if (res->backup) {
- BUG_ON(atomic_read(&res->backup->base.reserved) == 0);
- list_del_init(&res->mob_head);
- vmw_dmabuf_unreference(&res->backup);
- }
-
- res->backup = vmw_dmabuf_reference(new_backup);
- BUG_ON(atomic_read(&new_backup->base.reserved) == 0);
- list_add_tail(&res->mob_head, &new_backup->res_list);
- }
- if (new_backup)
- res->backup_offset = new_backup_offset;
-
- if (!res->func->may_evict)
- return;
-
- write_lock(&dev_priv->resource_lock);
- list_add_tail(&res->lru_head,
- &res->dev_priv->res_lru[res->func->res_type]);
- write_unlock(&dev_priv->resource_lock);
-}
-
-/**
- * vmw_resource_check_buffer - Check whether a backup buffer is needed
- * for a resource and in that case, allocate
- * one, reserve and validate it.
- *
- * @res: The resource for which to allocate a backup buffer.
- * @interruptible: Whether any sleeps during allocation should be
- * performed while interruptible.
- * @val_buf: On successful return contains data about the
- * reserved and validated backup buffer.
- */
-int vmw_resource_check_buffer(struct vmw_resource *res,
- bool interruptible,
- struct ttm_validate_buffer *val_buf)
-{
- struct list_head val_list;
- bool backup_dirty = false;
- int ret;
-
- if (unlikely(res->backup == NULL)) {
- ret = vmw_resource_buf_alloc(res, interruptible);
- if (unlikely(ret != 0))
- return ret;
- }
-
- INIT_LIST_HEAD(&val_list);
- val_buf->bo = ttm_bo_reference(&res->backup->base);
- list_add_tail(&val_buf->head, &val_list);
- ret = ttm_eu_reserve_buffers(&val_list);
- if (unlikely(ret != 0))
- goto out_no_reserve;
-
- if (res->func->needs_backup && list_empty(&res->mob_head))
- return 0;
-
- backup_dirty = res->backup_dirty;
- ret = ttm_bo_validate(&res->backup->base,
- res->func->backup_placement,
- true, false, false);
-
- if (unlikely(ret != 0))
- goto out_no_validate;
-
- return 0;
-
-out_no_validate:
- ttm_eu_backoff_reservation(&val_list);
-out_no_reserve:
- ttm_bo_unref(&val_buf->bo);
- if (backup_dirty)
- vmw_dmabuf_unreference(&res->backup);
-
- return ret;
-}
-
-/**
- * vmw_resource_reserve - Reserve a resource for command submission
- *
- * @res: The resource to reserve.
- *
- * This function takes the resource off the LRU list and make sure
- * a backup buffer is present for guest-backed resources. However,
- * the buffer may not be bound to the resource at this point.
- *
- */
-int vmw_resource_reserve(struct vmw_resource *res, bool no_backup)
-{
- struct vmw_private *dev_priv = res->dev_priv;
- int ret;
-
- write_lock(&dev_priv->resource_lock);
- list_del_init(&res->lru_head);
- write_unlock(&dev_priv->resource_lock);
-
- if (res->func->needs_backup && res->backup == NULL &&
- !no_backup) {
- ret = vmw_resource_buf_alloc(res, true);
- if (unlikely(ret != 0))
- return ret;
- }
-
- return 0;
-}
-
-/**
- * vmw_resource_backoff_reservation - Unreserve and unreference a
- * backup buffer
- *.
- * @val_buf: Backup buffer information.
- */
-void vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf)
-{
- struct list_head val_list;
-
- if (likely(val_buf->bo == NULL))
- return;
-
- INIT_LIST_HEAD(&val_list);
- list_add_tail(&val_buf->head, &val_list);
- ttm_eu_backoff_reservation(&val_list);
- ttm_bo_unref(&val_buf->bo);
-}
-
-/**
- * vmw_resource_do_evict - Evict a resource, and transfer its data
- * to a backup buffer.
- *
- * @res: The resource to evict.
- */
-int vmw_resource_do_evict(struct vmw_resource *res)
-{
- struct ttm_validate_buffer val_buf;
- const struct vmw_res_func *func = res->func;
- int ret;
-
- BUG_ON(!func->may_evict);
-
- val_buf.bo = NULL;
- ret = vmw_resource_check_buffer(res, true, &val_buf);
- if (unlikely(ret != 0))
- return ret;
-
- if (unlikely(func->unbind != NULL &&
- (!func->needs_backup || !list_empty(&res->mob_head)))) {
- ret = func->unbind(res, res->res_dirty, &val_buf);
- if (unlikely(ret != 0))
- goto out_no_unbind;
- list_del_init(&res->mob_head);
- }
- ret = func->destroy(res);
- res->backup_dirty = true;
- res->res_dirty = false;
-out_no_unbind:
- vmw_resource_backoff_reservation(&val_buf);
-
- return ret;
-}
-
-
-/**
- * vmw_resource_validate - Make a resource up-to-date and visible
- * to the device.
- *
- * @res: The resource to make visible to the device.
- *
- * On succesful return, any backup DMA buffer pointed to by @res->backup will
- * be reserved and validated.
- * On hardware resource shortage, this function will repeatedly evict
- * resources of the same type until the validation succeeds.
- */
-int vmw_resource_validate(struct vmw_resource *res)
-{
- int ret;
- struct vmw_resource *evict_res;
- struct vmw_private *dev_priv = res->dev_priv;
- struct list_head *lru_list = &dev_priv->res_lru[res->func->res_type];
- struct ttm_validate_buffer val_buf;
-
- if (likely(!res->func->may_evict))
- return 0;
-
- val_buf.bo = NULL;
- if (res->backup)
- val_buf.bo = &res->backup->base;
- do {
- ret = vmw_resource_do_validate(res, &val_buf);
- if (likely(ret != -EBUSY))
- break;
-
- write_lock(&dev_priv->resource_lock);
- if (list_empty(lru_list) || !res->func->may_evict) {
- DRM_ERROR("Out of device device id entries "
- "for %s.\n", res->func->type_name);
- ret = -EBUSY;
- write_unlock(&dev_priv->resource_lock);
- break;
- }
-
- evict_res = vmw_resource_reference
- (list_first_entry(lru_list, struct vmw_resource,
- lru_head));
- list_del_init(&evict_res->lru_head);
-
- write_unlock(&dev_priv->resource_lock);
- vmw_resource_do_evict(evict_res);
- vmw_resource_unreference(&evict_res);
- } while (1);
-
- if (unlikely(ret != 0))
- goto out_no_validate;
- else if (!res->func->needs_backup && res->backup) {
- list_del_init(&res->mob_head);
- vmw_dmabuf_unreference(&res->backup);
- }
-
- return 0;
-
-out_no_validate:
- return ret;
-}
-
-/**
- * vmw_fence_single_bo - Utility function to fence a single TTM buffer
- * object without unreserving it.
- *
- * @bo: Pointer to the struct ttm_buffer_object to fence.
- * @fence: Pointer to the fence. If NULL, this function will
- * insert a fence into the command stream..
- *
- * Contrary to the ttm_eu version of this function, it takes only
- * a single buffer object instead of a list, and it also doesn't
- * unreserve the buffer object, which needs to be done separately.
- */
-void vmw_fence_single_bo(struct ttm_buffer_object *bo,
- struct vmw_fence_obj *fence)
-{
- struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_bo_driver *driver = bdev->driver;
- struct vmw_fence_obj *old_fence_obj;
- struct vmw_private *dev_priv =
- container_of(bdev, struct vmw_private, bdev);
-
- if (fence == NULL)
- vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
- else
- driver->sync_obj_ref(fence);
-
- spin_lock(&bdev->fence_lock);
-
- old_fence_obj = bo->sync_obj;
- bo->sync_obj = fence;
-
- spin_unlock(&bdev->fence_lock);
-
- if (old_fence_obj)
- vmw_fence_obj_unreference(&old_fence_obj);
-}
-
-/**
- * vmw_resource_move_notify - TTM move_notify_callback
- *
- * @bo: The TTM buffer object about to move.
- * @mem: The truct ttm_mem_reg indicating to what memory
- * region the move is taking place.
- *
- * For now does nothing.
- */
-void vmw_resource_move_notify(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *mem)
-{
-}
-
-/**
- * vmw_resource_needs_backup - Return whether a resource needs a backup buffer.
- *
- * @res: The resource being queried.
- */
-bool vmw_resource_needs_backup(const struct vmw_resource *res)
-{
- return res->func->needs_backup;
-}
-
-/**
- * vmw_resource_evict_type - Evict all resources of a specific type
- *
- * @dev_priv: Pointer to a device private struct
- * @type: The resource type to evict
- *
- * To avoid thrashing starvation or as part of the hibernation sequence,
- * evict all evictable resources of a specific type.
- */
-static void vmw_resource_evict_type(struct vmw_private *dev_priv,
- enum vmw_res_type type)
-{
- struct list_head *lru_list = &dev_priv->res_lru[type];
- struct vmw_resource *evict_res;
-
- do {
- write_lock(&dev_priv->resource_lock);
-
- if (list_empty(lru_list))
- goto out_unlock;
-
- evict_res = vmw_resource_reference(
- list_first_entry(lru_list, struct vmw_resource,
- lru_head));
- list_del_init(&evict_res->lru_head);
- write_unlock(&dev_priv->resource_lock);
- vmw_resource_do_evict(evict_res);
- vmw_resource_unreference(&evict_res);
- } while (1);
-
-out_unlock:
- write_unlock(&dev_priv->resource_lock);
-}
-
-/**
- * vmw_resource_evict_all - Evict all evictable resources
- *
- * @dev_priv: Pointer to a device private struct
- *
- * To avoid thrashing starvation or as part of the hibernation sequence,
- * evict all evictable resources. In particular this means that all
- * guest-backed resources that are registered with the device are
- * evicted and the OTable becomes clean.
- */
-void vmw_resource_evict_all(struct vmw_private *dev_priv)
-{
- enum vmw_res_type type;
-
- mutex_lock(&dev_priv->cmdbuf_mutex);
-
- for (type = 0; type < vmw_res_max; ++type)
- vmw_resource_evict_type(dev_priv, type);
-
- mutex_unlock(&dev_priv->cmdbuf_mutex);
-}
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h
deleted file mode 100644
index f3adeed2854c..000000000000
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/**************************************************************************
- *
- * Copyright © 2012 VMware, Inc., Palo Alto, CA., USA
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-#ifndef _VMWGFX_RESOURCE_PRIV_H_
-#define _VMWGFX_RESOURCE_PRIV_H_
-
-#include "vmwgfx_drv.h"
-
-/**
- * struct vmw_user_resource_conv - Identify a derived user-exported resource
- * type and provide a function to convert its ttm_base_object pointer to
- * a struct vmw_resource
- */
-struct vmw_user_resource_conv {
- enum ttm_object_type object_type;
- struct vmw_resource *(*base_obj_to_res)(struct ttm_base_object *base);
- void (*res_free) (struct vmw_resource *res);
-};
-
-/**
- * struct vmw_res_func - members and functions common for a resource type
- *
- * @res_type: Enum that identifies the lru list to use for eviction.
- * @needs_backup: Whether the resource is guest-backed and needs
- * persistent buffer storage.
- * @type_name: String that identifies the resource type.
- * @backup_placement: TTM placement for backup buffers.
- * @may_evict Whether the resource may be evicted.
- * @create: Create a hardware resource.
- * @destroy: Destroy a hardware resource.
- * @bind: Bind a hardware resource to persistent buffer storage.
- * @unbind: Unbind a hardware resource from persistent
- * buffer storage.
- */
-
-struct vmw_res_func {
- enum vmw_res_type res_type;
- bool needs_backup;
- const char *type_name;
- struct ttm_placement *backup_placement;
- bool may_evict;
-
- int (*create) (struct vmw_resource *res);
- int (*destroy) (struct vmw_resource *res);
- int (*bind) (struct vmw_resource *res,
- struct ttm_validate_buffer *val_buf);
- int (*unbind) (struct vmw_resource *res,
- bool readback,
- struct ttm_validate_buffer *val_buf);
-};
-
-int vmw_resource_alloc_id(struct vmw_resource *res);
-void vmw_resource_release_id(struct vmw_resource *res);
-int vmw_resource_init(struct vmw_private *dev_priv, struct vmw_resource *res,
- bool delay_id,
- void (*res_free) (struct vmw_resource *res),
- const struct vmw_res_func *func);
-void vmw_resource_activate(struct vmw_resource *res,
- void (*hw_destroy) (struct vmw_resource *));
-#endif
diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
deleted file mode 100644
index 582814339748..000000000000
--- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ /dev/null
@@ -1,893 +0,0 @@
-/**************************************************************************
- *
- * Copyright © 2009-2012 VMware, Inc., Palo Alto, CA., USA
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-#include "vmwgfx_drv.h"
-#include "vmwgfx_resource_priv.h"
-#include