diff options
199 files changed, 45501 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 00000000..3be34625 --- /dev/null +++ b/Android.mk @@ -0,0 +1,531 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_reg_write.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_reg_map.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + +LOCAL_MODULE := intel_reg_write +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_reg_read.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_reg_map.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_reg_read +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_disable_clock_gating.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_disable_clock_gating +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_audio_dump.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_audio_dump +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_backlight.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_backlight +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_bios_dumper.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_bios_dumper +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_bios_reader.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_bios_reader +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +# Disabling intel_error_decode tool, since Android still does not have libdrm2.4.30 +#================ +#include $(CLEAR_VARS) +# +#LOCAL_SRC_FILES := \ +# tools/intel_error_decode.c \ +# lib/intel_pci.c \ +# lib/intel_gpu_tools.h \ +# tools/intel_reg.h \ +# lib/intel_batchbuffer.h \ +# lib/intel_batchbuffer.c \ +# lib/intel_mmio.c \ +# tools/intel_chipset.h \ +# lib/instdone.h \ +# lib/instdone.c \ +# tools/intel_decode.h \ +# lib/intel_drm.c +# +# +#LOCAL_C_INCLUDES += \ +# $(LOCAL_PATH)/lib \ +# $(TOPDIR)hardware/intel/libdrm/include/drm \ +# $(TOPDIR)hardware/intel/libdrm/intel \ +# $(LOCAL_PATH)/../libpciaccess/include/ +# +#LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +#LOCAL_CFLAGS += -DANDROID +#LOCAL_CFLAGS += -std=c99 +# +# +#LOCAL_MODULE := intel_error_decode +#LOCAL_MODULE_TAGS := optional +# +#LOCAL_SHARED_LIBRARIES := libpciaccess \ +# libdrm \ +# libdrm_intel +# +#include $(BUILD_EXECUTABLE) +# +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_gpu_top.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h \ + lib/instdone.h \ + lib/instdone.c \ + lib/intel_reg_map.c + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_gpu_top +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_gpu_time.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_gpu_time +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_gtt.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 + +LOCAL_MODULE := intel_gtt +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_stepping.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_stepping +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_reg_dumper.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_reg_dumper +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/intel_reg_snapshot.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 + +LOCAL_MODULE := intel_reg_snapshot +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + tools/forcewaked.c \ + lib/intel_pci.c \ + lib/intel_gpu_tools.h \ + tools/intel_reg.h \ + lib/intel_batchbuffer.h \ + lib/intel_batchbuffer.c \ + lib/intel_mmio.c \ + tools/intel_chipset.h \ + lib/intel_reg_map.c \ + lib/intel_drm.c + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := forcewaked +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess \ + libdrm \ + libdrm_intel + +include $(BUILD_EXECUTABLE) + +#================ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + lib/intel_gpu_tools.h \ + tools/intel_reg_checker.c \ + lib/intel_pci.c \ + lib/intel_mmio.c + + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/lib \ + $(TOPDIR)hardware/intel/libdrm/include/drm \ + $(TOPDIR)hardware/intel/libdrm/intel \ + $(LOCAL_PATH)/../libpciaccess/include/ + +LOCAL_CFLAGS += -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 +LOCAL_CFLAGS += -DANDROID + + +LOCAL_MODULE := intel_reg_checker +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libpciaccess + +include $(BUILD_EXECUTABLE) + diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..b8f67535 --- /dev/null +++ b/COPYING @@ -0,0 +1,108 @@ +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +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 PRECISION INSIGHT 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. + +Copyright 2003,2006 Tungsten Graphics, Inc., Cedar Park, Texas. +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 TUNGSTEN GRAPHICS 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. + +Copyright © 2006-2011 Intel Corporation + +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 AUTHORS OR COPYRIGHT HOLDERS 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. + +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 (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 AUTHORS OR COPYRIGHT HOLDERS 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. + +Copyright © 2011 Daniel Vetter + +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 AUTHORS OR COPYRIGHT HOLDERS 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. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..5ea0fd87 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,43 @@ +# Copyright © 2005 Adam Jackson. +# Copyright © 2009 Intel Corporation +# +# 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 +# on 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 +# ADAM JACKSON 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. + +ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} + +SUBDIRS = lib man tools scripts tests benchmarks demos + +if BUILD_SHADER_DEBUGGER +SUBDIRS += debugger +endif + +test: + ${MAKE} -C tests test + +MAINTAINERCLEANFILES = ChangeLog INSTALL + +.PHONY: ChangeLog INSTALL + +INSTALL: + $(INSTALL_CMD) + +ChangeLog: + $(CHANGELOG_CMD) + +dist-hook: ChangeLog INSTALL @@ -0,0 +1,61 @@ +This is a collection of tools for development and testing of the Intel DRM +driver. There are many macro-level test suites that get used against our +driver, including xtest, rendercheck, piglit, and oglconform, but failures +from those can be difficult to track down to kernel changes, and many require +complicated build procedures or specific testing environments to get useful +results. + +Thus, intel-graphics-tools was a project I started to collect some low-level +tools I intended to build. + +benchmarks/ + This should be a collection of useful microbenchmarks. The hope is + that people can use these to tune some pieces of DRM code in relevant + ways. + + The benchmarks require KMS to be enabled. When run with an X Server + running, they must be run as root to avoid the authentication + requirement. + + Note that a few other microbenchmarks are in tests (like gem_gtt_speed). + +tests/ + This is a set of automated tests to run against the DRM to validate + changes. Hopefully this can cover the relevant cases we need to + worry about, including backwards compatibility. + + Run this tests with "make test" as root from this directory. Note that + no other drm clients (X server) may run. + + "make test" only runs a default of test usefull for regression testing. + Other tests not run are: + - tests that might hang the gpu, see HANG in Makefile.am + - gem_stress, a stress test suite. Look at the source for all the + various options. + - testdisplay is only run in the default mode. testdisplay has tons of + options to test different kms functionality, again read the source of + the details. + +lib/ + Common helper functions and headers used by the other tools. + +man/ + Manpages, unfortunately rather incomplete. + +tools/ + This is a collection of debugging tools that had previously been + built with the 2D driver but not shipped. Some distros were hacking + up the 2D build to ship them. Instead, here's a separate package for + people debugging the driver. + + These tools generally must be run as root, safe for the ones that just + decode dumps. + +debugger/ + This tool is to be used to do shader debugging. It acts like a + debug server accepting connections from debug clients such as + mesa. The connections is made with unix domain sockets, and at some + point it would be nice if this directory contained a library for + initiating connections with debug clients.. + + The debugger must be run as root: "sudo debugger/eudb" diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 00000000..904cd674 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,12 @@ +#! /bin/sh + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir + +autoreconf -v --install || exit 1 +cd $ORIGDIR || exit $? + +$srcdir/configure --enable-maintainer-mode "$@" diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore new file mode 100644 index 00000000..ddea6f7e --- /dev/null +++ b/benchmarks/.gitignore @@ -0,0 +1,5 @@ +intel_upload_blit_large +intel_upload_blit_large_gtt +intel_upload_blit_large_map +intel_upload_blit_small +# Please keep sorted alphabetically diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am new file mode 100644 index 00000000..e2ad7845 --- /dev/null +++ b/benchmarks/Makefile.am @@ -0,0 +1,10 @@ + +bin_PROGRAMS = \ + intel_upload_blit_large \ + intel_upload_blit_large_gtt \ + intel_upload_blit_large_map \ + intel_upload_blit_small + +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib +AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) +LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) diff --git a/benchmarks/intel_upload_blit_large.c b/benchmarks/intel_upload_blit_large.c new file mode 100644 index 00000000..de0f6683 --- /dev/null +++ b/benchmarks/intel_upload_blit_large.c @@ -0,0 +1,161 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** + * Roughly simulates repeatedly uploading frames of images, by uploading + * the data all at once with pwrite, and then blitting it to another buffer. + * + * You might think of this like a movie player, but that wouldn't be entirely + * accurate, since the access patterns of the memory would be different + * (generally, smaller source image, upscaled, an thus different memory access + * pattern in both texel fetch for the stretching and the destination writes). + * However, some things like swfdec would be doing something like this since + * they compute their data in host memory and upload the full sw rendered + * frame. + * + * Additionally, those applications should be rendering at the screen refresh + * rate, while this test has no limits, and so can get itself into the + * working set larger than aperture size performance disaster. + * + * The current workload doing this path is pixmap upload for non-KMS. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +#define OBJECT_WIDTH 1280 +#define OBJECT_HEIGHT 720 + +static double +get_time_in_secs(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return (double)tv.tv_sec + tv.tv_usec / 1000000.0; +} + +static void +do_render(drm_intel_bufmgr *bufmgr, struct intel_batchbuffer *batch, + drm_intel_bo *dst_bo, int width, int height) +{ + uint32_t data[width * height]; + drm_intel_bo *src_bo; + int i; + static uint32_t seed = 1; + + /* Generate some junk. Real workloads would be doing a lot more + * work to generate the junk. + */ + for (i = 0; i < width * height; i++) { + data[i] = seed++; + } + + /* Upload the junk. */ + src_bo = drm_intel_bo_alloc(bufmgr, "src", sizeof(data), 4096); + drm_intel_bo_subdata(src_bo, 0, sizeof(data), data); + + /* Render the junk to the dst. */ + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + (width * 4) /* dst pitch */); + OUT_BATCH(0); /* dst x1,y1 */ + OUT_BATCH((height << 16) | width); /* dst x2,y2 */ + OUT_RELOC(dst_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0); /* src x1,y1 */ + OUT_BATCH(width * 4); /* src pitch */ + OUT_RELOC(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); + + drm_intel_bo_unreference(src_bo); +} + +int main(int argc, char **argv) +{ + int fd; + int object_size = OBJECT_WIDTH * OBJECT_HEIGHT * 4; + double start_time, end_time; + drm_intel_bo *dst_bo; + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + int i; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + dst_bo = drm_intel_bo_alloc(bufmgr, "dst", object_size, 4096); + + /* Prep loop to get us warmed up. */ + for (i = 0; i < 60; i++) { + do_render(bufmgr, batch, dst_bo, OBJECT_WIDTH, OBJECT_HEIGHT); + } + drm_intel_bo_wait_rendering(dst_bo); + + /* Do the actual timing. */ + start_time = get_time_in_secs(); + for (i = 0; i < 200; i++) { + do_render(bufmgr, batch, dst_bo, OBJECT_WIDTH, OBJECT_HEIGHT); + } + drm_intel_bo_wait_rendering(dst_bo); + end_time = get_time_in_secs(); + + printf("%d iterations in %.03f secs: %.01f MB/sec\n", i, + end_time - start_time, + (double)i * OBJECT_WIDTH * OBJECT_HEIGHT * 4 / 1024.0 / 1024.0 / + (end_time - start_time)); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/benchmarks/intel_upload_blit_large_gtt.c b/benchmarks/intel_upload_blit_large_gtt.c new file mode 100644 index 00000000..dc2733e2 --- /dev/null +++ b/benchmarks/intel_upload_blit_large_gtt.c @@ -0,0 +1,161 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** + * Roughly simulates repeatedly uploading frames of images, by uploading + * the data all at once with pwrite, and then blitting it to another buffer. + * + * You might think of this like a movie player, but that wouldn't be entirely + * accurate, since the access patterns of the memory would be different + * (generally, smaller source image, upscaled, an thus different memory access + * pattern in both texel fetch for the stretching and the destination writes). + * However, some things like swfdec would be doing something like this since + * they compute their data in host memory and upload the full sw rendered + * frame. + * + * Additionally, those applications should be rendering at the screen refresh + * rate, while this test has no limits, and so can get itself into the + * working set larger than aperture size performance disaster. + * + * The current workload doing this path is pixmap upload in 2D with KMS. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +#define OBJECT_WIDTH 1280 +#define OBJECT_HEIGHT 720 + +static double +get_time_in_secs(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return (double)tv.tv_sec + tv.tv_usec / 1000000.0; +} + +static void +do_render(drm_intel_bufmgr *bufmgr, struct intel_batchbuffer *batch, + drm_intel_bo *dst_bo, int width, int height) +{ + uint32_t *data; + drm_intel_bo *src_bo; + int i; + static uint32_t seed = 1; + + src_bo = drm_intel_bo_alloc(bufmgr, "src", width * height * 4, 4096); + + drm_intel_gem_bo_map_gtt(src_bo); + + data = src_bo->virtual; + for (i = 0; i < width * height; i++) { + data[i] = seed++; + } + + drm_intel_gem_bo_unmap_gtt(src_bo); + + /* Render the junk to the dst. */ + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + (width * 4) /* dst pitch */); + OUT_BATCH(0); /* dst x1,y1 */ + OUT_BATCH((height << 16) | width); /* dst x2,y2 */ + OUT_RELOC(dst_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0); /* src x1,y1 */ + OUT_BATCH(width * 4); /* src pitch */ + OUT_RELOC(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); + + drm_intel_bo_unreference(src_bo); +} + +int main(int argc, char **argv) +{ + int fd; + int object_size = OBJECT_WIDTH * OBJECT_HEIGHT * 4; + double start_time, end_time; + drm_intel_bo *dst_bo; + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + int i; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + dst_bo = drm_intel_bo_alloc(bufmgr, "dst", object_size, 4096); + + /* Prep loop to get us warmed up. */ + for (i = 0; i < 60; i++) { + do_render(bufmgr, batch, dst_bo, OBJECT_WIDTH, OBJECT_HEIGHT); + } + drm_intel_bo_wait_rendering(dst_bo); + + /* Do the actual timing. */ + start_time = get_time_in_secs(); + for (i = 0; i < 200; i++) { + do_render(bufmgr, batch, dst_bo, OBJECT_WIDTH, OBJECT_HEIGHT); + } + drm_intel_bo_wait_rendering(dst_bo); + end_time = get_time_in_secs(); + + printf("%d iterations in %.03f secs: %.01f MB/sec\n", i, + end_time - start_time, + (double)i * OBJECT_WIDTH * OBJECT_HEIGHT * 4 / 1024.0 / 1024.0 / + (end_time - start_time)); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/benchmarks/intel_upload_blit_large_map.c b/benchmarks/intel_upload_blit_large_map.c new file mode 100644 index 00000000..0ca9e9de --- /dev/null +++ b/benchmarks/intel_upload_blit_large_map.c @@ -0,0 +1,164 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** + * Roughly simulates repeatedly uploading frames of images, by uploading + * the data all at once with pwrite, and then blitting it to another buffer. + * + * You might think of this like a movie player, but that wouldn't be entirely + * accurate, since the access patterns of the memory would be different + * (generally, smaller source image, upscaled, an thus different memory access + * pattern in both texel fetch for the stretching and the destination writes). + * However, some things like swfdec would be doing something like this since + * they compute their data in host memory and upload the full sw rendered + * frame. + * + * Additionally, those applications should be rendering at the screen refresh + * rate, while this test has no limits, and so can get itself into the + * working set larger than aperture size performance disaster. + * + * The current workload we have that does large drm_intel_bo_map() + * uploads is texture upload for OpenGL (as it frequently is doing + * reformatting as it uploads the user's data, making bo_subdata less + * suitable) + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +#define OBJECT_WIDTH 1280 +#define OBJECT_HEIGHT 720 + +static double +get_time_in_secs(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return (double)tv.tv_sec + tv.tv_usec / 1000000.0; +} + +static void +do_render(drm_intel_bufmgr *bufmgr, struct intel_batchbuffer *batch, + drm_intel_bo *dst_bo, int width, int height) +{ + uint32_t *data; + drm_intel_bo *src_bo; + int i; + static uint32_t seed = 1; + + src_bo = drm_intel_bo_alloc(bufmgr, "src", width * height * 4, 4096); + + drm_intel_bo_map(src_bo, 1); + + data = src_bo->virtual; + for (i = 0; i < width * height; i++) { + data[i] = seed++; + } + + drm_intel_bo_unmap(src_bo); + + /* Render the junk to the dst. */ + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + (width * 4) /* dst pitch */); + OUT_BATCH(0); /* dst x1,y1 */ + OUT_BATCH((height << 16) | width); /* dst x2,y2 */ + OUT_RELOC(dst_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0); /* src x1,y1 */ + OUT_BATCH(width * 4); /* src pitch */ + OUT_RELOC(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); + + drm_intel_bo_unreference(src_bo); +} + +int main(int argc, char **argv) +{ + int fd; + int object_size = OBJECT_WIDTH * OBJECT_HEIGHT * 4; + double start_time, end_time; + drm_intel_bo *dst_bo; + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + int i; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + dst_bo = drm_intel_bo_alloc(bufmgr, "dst", object_size, 4096); + + /* Prep loop to get us warmed up. */ + for (i = 0; i < 60; i++) { + do_render(bufmgr, batch, dst_bo, OBJECT_WIDTH, OBJECT_HEIGHT); + } + drm_intel_bo_wait_rendering(dst_bo); + + /* Do the actual timing. */ + start_time = get_time_in_secs(); + for (i = 0; i < 200; i++) { + do_render(bufmgr, batch, dst_bo, OBJECT_WIDTH, OBJECT_HEIGHT); + } + drm_intel_bo_wait_rendering(dst_bo); + end_time = get_time_in_secs(); + + printf("%d iterations in %.03f secs: %.01f MB/sec\n", i, + end_time - start_time, + (double)i * OBJECT_WIDTH * OBJECT_HEIGHT * 4 / 1024.0 / 1024.0 / + (end_time - start_time)); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/benchmarks/intel_upload_blit_small.c b/benchmarks/intel_upload_blit_small.c new file mode 100644 index 00000000..8ad25ad1 --- /dev/null +++ b/benchmarks/intel_upload_blit_small.c @@ -0,0 +1,174 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** + * Roughly simulates Mesa's current vertex buffer behavior: do a series of + * small pwrites on a moderately-sized buffer, then render using it. + * + * The vertex buffer uploads + * + * You might think of this like a movie player, but that wouldn't be entirely + * accurate, since the access patterns of the memory would be different + * (generally, smaller source image, upscaled, an thus different memory access + * pattern in both texel fetch for the stretching and the destination writes). + * However, some things like swfdec would be doing something like this since + * they compute their data in host memory and upload the full sw rendered + * frame. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +/* Happens to be 128k, the size of the VBOs used by i965's Mesa driver. */ +#define OBJECT_WIDTH 256 +#define OBJECT_HEIGHT 128 + +static double +get_time_in_secs(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return (double)tv.tv_sec + tv.tv_usec / 1000000.0; +} + +static void +do_render(drm_intel_bufmgr *bufmgr, struct intel_batchbuffer *batch, + drm_intel_bo *dst_bo, int width, int height) +{ + uint32_t data[64]; + drm_intel_bo *src_bo; + int i; + static uint32_t seed = 1; + + src_bo = drm_intel_bo_alloc(bufmgr, "src", width * height * 4, 4096); + + /* Upload some junk. Real workloads would be doing a lot more + * work to generate the junk. + */ + for (i = 0; i < width * height;) { + int size, j; + + /* Choose a size from 1 to 64 dwords to upload. + * Normal workloads have a distribution of sizes with a + * large tail (something in your scene's going to have a big + * pile of vertices, most likely), but I'm trying to get at + * the cost of the small uploads here. + */ + size = random() % 64 + 1; + if (i + size > width * height) + size = width * height - i; + + for (j = 0; j < size; j++) + data[j] = seed++; + + /* Upload the junk. */ + drm_intel_bo_subdata(src_bo, i * 4, size * 4, data); + + i += size; + } + + /* Render the junk to the dst. */ + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + (width * 4) /* dst pitch */); + OUT_BATCH(0); /* dst x1,y1 */ + OUT_BATCH((height << 16) | width); /* dst x2,y2 */ + OUT_RELOC(dst_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0); /* src x1,y1 */ + OUT_BATCH(width * 4); /* src pitch */ + OUT_RELOC(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); + + drm_intel_bo_unreference(src_bo); +} + +int main(int argc, char **argv) +{ + int fd; + int object_size = OBJECT_WIDTH * OBJECT_HEIGHT * 4; + double start_time, end_time; + drm_intel_bo *dst_bo; + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + int i; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + dst_bo = drm_intel_bo_alloc(bufmgr, "dst", object_size, 4096); + + /* Prep loop to get us warmed up. */ + for (i = 0; i < 20; i++) { + do_render(bufmgr, batch, dst_bo, OBJECT_WIDTH, OBJECT_HEIGHT); + } + drm_intel_bo_wait_rendering(dst_bo); + + /* Do the actual timing. */ + start_time = get_time_in_secs(); + for (i = 0; i < 1000; i++) { + do_render(bufmgr, batch, dst_bo, OBJECT_WIDTH, OBJECT_HEIGHT); + } + drm_intel_bo_wait_rendering(dst_bo); + end_time = get_time_in_secs(); + + printf("%d iterations in %.03f secs: %.01f MB/sec\n", i, + end_time - start_time, + (double)i * OBJECT_WIDTH * OBJECT_HEIGHT * 4 / 1024.0 / 1024.0 / + (end_time - start_time)); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..0ba7ce76 --- /dev/null +++ b/configure.ac @@ -0,0 +1,139 @@ +# Copyright 2005 Adam Jackson. +# +# 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 +# on 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 +# ADAM JACKSON 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. +# +# Process this file with autoconf to produce a configure script + +AC_PREREQ([2.60]) +AC_INIT([intel-gpu-tools], + [1.3], + [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], + [intel-gpu-tools]) + +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_USE_SYSTEM_EXTENSIONS +AC_SYS_LARGEFILE +AC_GNU_SOURCE + +AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_PATH_PYTHON([3],, [:]) +AM_MAINTAINER_MODE + +# Checks for functions, headers, structures, etc. +AC_CHECK_HEADERS([termios.h]) +AC_CHECK_MEMBERS([struct sysinfo.totalram],[],[],[AC_INCLUDES_DEFAULT +#include <sys/sysinfo.h> +]) +AC_CHECK_FUNCS([swapctl]) +AC_CHECK_FUNCS([asprintf]) + +# Initialize libtool +AC_DISABLE_STATIC +AC_PROG_LIBTOOL + +# Require X.Org macros 1.16 or later for XORG_TESTSET_CFLAG +m4_ifndef([XORG_MACROS_VERSION], + [m4_fatal([must install xorg-macros 1.16 or later before running autoconf/autogen])]) +XORG_MACROS_VERSION(1.16) +XORG_DEFAULT_OPTIONS + +PKG_CHECK_MODULES(DRM, [libdrm_intel >= 2.4.38 libdrm]) +PKG_CHECK_MODULES(PCIACCESS, [pciaccess >= 0.10]) + +# for dma-buf tests +AC_ARG_ENABLE(nouveau, + AS_HELP_STRING([--disable-nouveau], + [Enable use of nouveau API for prime tests (default: enabled)]), + [NOUVEAU=$enableval], [NOUVEAU=yes]) +if test "x$NOUVEAU" = xyes; then + PKG_CHECK_MODULES(DRM_NOUVEAU, [libdrm_nouveau >= 2.4.33]) + AC_DEFINE(HAVE_NOUVEAU, 1, [Have nouveau support]) +fi +AM_CONDITIONAL(HAVE_NOUVEAU, [test "x$NOUVEAU" = xyes]) + + +# for testdisplay +PKG_CHECK_MODULES(CAIRO, cairo) +PKG_CHECK_MODULES(LIBUDEV, [libudev], [udev=yes], [udev=no]) +if test x"$udev" = xyes; then + AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection]) +fi +PKG_CHECK_MODULES(GLIB, glib-2.0) + +# ----------------------------------------------------------------------------- +# Configuration options +# ----------------------------------------------------------------------------- +# Define a configure option for the shadder debugger +AC_ARG_ENABLE(shader-debugger, AS_HELP_STRING([--enable-shader-debugger], + [Enable shader debugging support [autodetected]]), + [BUILD_SHADER_DEBUGGER="$enableval"], [BUILD_SHADER_DEBUGGER=auto]) + +# Shadder debugger depends on python3, intel-genasm and objcopy +if test "x$BUILD_SHADER_DEBUGGER" != xno; then + # Check Python 3 is installed + if test "$PYTHON" = ":" ; then + if test "x$BUILD_SHADER_DEBUGGER" = xyes; then + AC_MSG_ERROR([Shader debugger requested, python version 3 not found.]) + else + BUILD_SHADER_DEBUGGER=no + fi + fi + # Check for the Intel Chipset assembler compiler + AC_PATH_PROGS([GEN4ASM], intel-gen4asm) + if test -z "$GEN4ASM" ; then + if test "x$BUILD_SHADER_DEBUGGER" = xyes; then + AC_MSG_ERROR([Shader debugger requested, but intel-gen4asm not found.]) + else + BUILD_SHADER_DEBUGGER=no + fi + fi + # Check for the objcopy GNU binary utiliy command + AC_PATH_PROGS([OBJCOPY], objcopy) + if test -z "$OBJCOPY" ; then + if test "x$BUILD_SHADER_DEBUGGER" = xyes; then + AC_MSG_ERROR([Shader debugger requested, but objcopy command not found.]) + else + BUILD_SHADER_DEBUGGER=no + fi + fi +fi + +AM_CONDITIONAL(BUILD_SHADER_DEBUGGER, [test "x$BUILD_SHADER_DEBUGGER" != xno]) +# ----------------------------------------------------------------------------- + +# To build multithread code, gcc uses -pthread, Solaris Studio cc uses -mt +XORG_TESTSET_CFLAG([THREAD_CFLAGS], [-pthread], [-mt]) +AC_SUBST([THREAD_CFLAGS]) + +AC_CONFIG_FILES([ + Makefile + benchmarks/Makefile + demos/Makefile + lib/Makefile + man/Makefile + scripts/Makefile + tests/Makefile + tools/Makefile + debugger/Makefile + debugger/system_routine/Makefile +]) +AC_OUTPUT diff --git a/debugger/.gitignore b/debugger/.gitignore new file mode 100644 index 00000000..873cd273 --- /dev/null +++ b/debugger/.gitignore @@ -0,0 +1,2 @@ +debug_rdata +eudb diff --git a/debugger/Makefile.am b/debugger/Makefile.am new file mode 100644 index 00000000..d76e2ac6 --- /dev/null +++ b/debugger/Makefile.am @@ -0,0 +1,16 @@ + +SUBDIRS = system_routine + +bin_PROGRAMS = eudb +noinst_PROGRAMS = debug_rdata + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/lib + +AM_CFLAGS = \ + $(DRM_CFLAGS) \ + $(PCIACCESS_CFLAGS) \ + $(CWARNFLAGS) + +LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) diff --git a/debugger/debug_rdata.c b/debugger/debug_rdata.c new file mode 100644 index 00000000..f7dc4245 --- /dev/null +++ b/debugger/debug_rdata.c @@ -0,0 +1,141 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include "intel_gpu_tools.h" + +struct eu_rdata { + union { + struct { + uint8_t sendc_dep : 1; + uint8_t swh_dep : 1; + uint8_t pwc_dep : 1; + uint8_t n2_dep : 1; + uint8_t n1_dep : 1; + uint8_t n0_dep : 1; + uint8_t flag1_dep : 1; + uint8_t flag0_dep : 1; + uint8_t indx_dep : 1; + uint8_t mrf_dep : 1; + uint8_t dst_dep : 1; + uint8_t src2_dep : 1; + uint8_t src1_dep : 1; + uint8_t src0_dep : 1; + uint8_t mp_dep_pin : 1; + uint8_t sp_dep_pin : 1; + uint8_t fftid : 8; + uint8_t ffid : 4; + uint8_t instruction_valid : 1; + uint8_t thread_status : 3; + }; + uint32_t dword; + } ud0; + + union { + struct { + uint8_t mrf_addr : 4; + uint8_t dst_addr : 7; + uint8_t src2_addr : 7; + uint8_t src1_addr : 7; + uint8_t src0_addr : 7; + }; + uint32_t dword; + } ud1; + + union { + struct { + uint16_t exip : 12; + uint8_t opcode : 7; + uint8_t pwc : 8; + uint8_t instruction_valid : 1; + uint8_t mbz : 4; + }; + uint32_t dword; + } ud2; +}; + +const char *thread_status[] = + {"INVALID", "invalid/no thread", "standby (dependency)", "INVALID", "Executing", + "INVALID" , "INVALID" , "INVALID"}; + +static struct eu_rdata +collect_rdata(int eu, int tid) { + struct eu_rdata rdata; + + intel_register_write(0x7800, eu << 16 | (3 * tid) << 8); + rdata.ud0.dword = intel_register_read(0x7840); + + intel_register_write(0x7800, eu << 16 | (3 * tid + 1) << 8); + rdata.ud1.dword = intel_register_read(0x7840); + + intel_register_write(0x7800, eu << 16 | (3 * tid + 2) << 8); + rdata.ud2.dword = intel_register_read(0x7840); + + return rdata; +} +static void +print_rdata(struct eu_rdata rdata) { + printf("\t%s\n", thread_status[rdata.ud0.thread_status]); + printf("\tn1_dep: %d\n", rdata.ud0.n1_dep); + printf("\tpwc_dep: %d\n", rdata.ud0.pwc_dep); + printf("\tswh_dep: %d\n", rdata.ud0.swh_dep); + printf("\tsource 0 %x\n", rdata.ud1.src0_addr); + printf("\tsource 1 %x\n", rdata.ud1.src1_addr); + printf("\tsource 2 %x\n", rdata.ud1.src2_addr); + printf("\tdest %x\n", rdata.ud1.dst_addr); + printf("\tmrf %x\n", rdata.ud1.mrf_addr); + printf("\tIP: %x\n", rdata.ud2.exip); + printf("\topcode: %x\n", rdata.ud2.opcode); +} + +static void +find_stuck_threads(void) +{ + int i, j; + for (i = 0; i < 15; i++) + for (j = 0; j < 5; j++) { + struct eu_rdata rdata; + rdata = collect_rdata(i, j); + if (rdata.ud0.thread_status == 2 || + rdata.ud0.thread_status == 4) { + printf("%d %d:\n", i, j); + print_rdata(rdata); + } + } +} + +int main(int argc, char *argv[]) { + struct pci_device *pci_dev; + pci_dev = intel_get_pci_device(); + + intel_register_access_init(pci_dev, 1); + find_stuck_threads(); +// collect_rdata(atoi(argv[1]), atoi(argv[2])); + return 0; +} diff --git a/debugger/eudb.c b/debugger/eudb.c new file mode 100644 index 00000000..228a143f --- /dev/null +++ b/debugger/eudb.c @@ -0,0 +1,606 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + * Notes: + * + */ + +#include <signal.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <strings.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/un.h> +#include <sys/socket.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_chipset.h" +#include "intel_bufmgr.h" +#include "intel_gpu_tools.h" +#include "intel_batchbuffer.h" +#include "intel_debug.h" +#include "debug.h" + +#define EU_ATT 0x7810 +#define EU_ATT_CLR 0x7830 + +#define RSVD_EU -1 +#define RSVD_THREAD -1 +#define RSVD_ID EUID(-1, -1, -1) + +enum { + EBAD_SHMEM, + EBAD_PROTOCOL, + EBAD_MAGIC, + EBAD_WRITE +}; + +struct debuggee { + int euid; + int tid; + int fd; + int clr; + uint32_t reg; +}; + +struct debugger { + struct debuggee *debuggees; + int num_threads; + int real_num_threads; + int threads_per_eu; +} *eu_info; + +drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +drm_intel_bo *scratch_bo; + +int handle; +int drm_fd; +int debug_fd = 0; +const char *debug_file = "dump_debug.bin"; +int debug; +int clear_waits; +int shutting_down = 0; +struct intel_debug_handshake dh; +int force_clear = 0; +uint32_t old_td_ctl; + +/* + * The docs are wrong about the attention clear bits. The clear bits are + * provided as part of the structure in case they change in future generations. + */ +#define EUID(eu, td, clear) \ + { .euid = eu, .tid = td, .reg = EU_ATT, .fd = -1, .clr = clear } +#define EUID2(eu, td, clear) \ + { .euid = eu, .tid = td, .reg = EU_ATT + 4, .fd = -1, .clr = clear } +struct debuggee gt1_debug_ids[] = { + RSVD_ID, RSVD_ID, + RSVD_ID, EUID(6, 3, 28), EUID(6, 2, 27), EUID(6, 1, 26), EUID(6, 0, 25), + RSVD_ID, EUID(5, 3, 23), EUID(5, 2, 22), EUID(5, 1, 21), EUID(5, 0, 20), + RSVD_ID, EUID(4, 3, 18), EUID(4, 2, 17), EUID(4, 1, 16), EUID(4, 0, 15), + RSVD_ID, EUID(2, 3, 13), EUID(2, 2, 12), EUID(2, 1, 11), EUID(2, 0, 10), + RSVD_ID, EUID(1, 3, 8), EUID(1, 2, 7), EUID(1, 1, 6), EUID(1, 0, 5), + RSVD_ID, EUID(0, 3, 3), EUID(0, 2, 2), EUID(0, 1, 1), EUID(0, 0, 0) +}; + +struct debuggee gt2_debug_ids[] = { + EUID(8, 1, 31), EUID(8, 0, 30), + EUID(6, 4, 29), EUID(6, 3, 28), EUID(6, 2, 27), EUID(6, 1, 26), EUID(6, 0, 25), + EUID(5, 4, 24), EUID(5, 3, 23), EUID(5, 2, 22), EUID(5, 1, 21), EUID(5, 0, 20), + EUID(4, 4, 19), EUID(4, 3, 18), EUID(4, 2, 17), EUID(4, 1, 16), EUID(4, 0, 15), + EUID(2, 4, 14), EUID(2, 3, 13), EUID(2, 2, 12), EUID(2, 1, 11), EUID(2, 0, 10), + EUID(1, 4, 9), EUID(1, 3, 8), EUID(1, 2, 7), EUID(1, 1, 6), EUID(1, 0, 5), + EUID(0, 4, 4), EUID(0, 3, 3), EUID(0, 2, 2), EUID(0, 1, 1), EUID(0, 0, 0), + RSVD_ID, RSVD_ID, RSVD_ID, RSVD_ID, + EUID2(14, 4, 27), EUID2(14, 3, 26), EUID2(14, 2, 25), EUID2(14, 1, 24), EUID2(14, 0, 23), + EUID2(13, 4, 22), EUID2(13, 3, 21), EUID2(13, 2, 20), EUID2(13, 1, 19), EUID2(13, 0, 18), + EUID2(12, 4, 17), EUID2(12, 3, 16), EUID2(12, 2, 15), EUID2(12, 1, 14), EUID2(12, 0, 13), + EUID2(10, 4, 12), EUID2(10, 3, 11), EUID2(10, 2, 10), EUID2(10, 1, 9), EUID2(10, 0, 8), + EUID2(9, 4, 7), EUID2(9, 3, 6), EUID2(9, 2, 5), EUID2(9, 1, 4), EUID2(9, 0, 3), + EUID2(8, 4, 2), EUID2(8, 3, 1), EUID2(8, 2, 0) +}; + +struct debugger gt1 = { + .debuggees = gt1_debug_ids, + .num_threads = 32, + .real_num_threads = 24, + .threads_per_eu = 4 +}; + +struct debugger gt2 = { + .debuggees = gt2_debug_ids, + .num_threads = 64, + .real_num_threads = 60, + .threads_per_eu = 5 +}; + +static void +dump_debug(void *buf, size_t count) { + if (!debug_fd) + debug_fd = open(debug_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXO); + + write(debug_fd, buf, count); +} + +static volatile void * +map_debug_buffer(void) { + int ret; + + ret = drm_intel_bo_map(scratch_bo, 0); + assert(ret == 0); + return scratch_bo->virtual; +} + +static void +unmap_debug_buffer(void) { + drm_intel_bo_unmap(scratch_bo); +} + +static int +wait_for_attn(int timeout, int *out_bits) { + int step = 1; + int eus_waiting = 0; + int i,j; + + if (timeout <= 0) { + timeout = 1; + step = 0; + } + + for (i = 0; i < timeout; i += step) { + for (j = 0; j < 8; j += 4) { + uint32_t attn = intel_register_read(EU_ATT + j); + if (attn) { + int bit = 0; + while( (bit = ffs(attn)) != 0) { + bit--; // ffs is 1 based + assert(bit >= 0); + out_bits[eus_waiting] = bit + (j * 8); + attn &= ~(1 << bit); + eus_waiting++; + } + } + } + + if (intel_register_read(EU_ATT + 8) || + intel_register_read(EU_ATT + 0xc)) { + fprintf(stderr, "Unknown attention bits\n"); + } + + if (eus_waiting || shutting_down) + break; + } + + return eus_waiting; +} + +#define eu_fd(bit) eu_info->debuggees[bit].fd +#define eu_id(bit) eu_info->debuggees[bit].euid +#define eu_tid(bit) eu_info->debuggees[bit].tid +static struct eu_state * +find_eu_shmem(int bit, volatile uint8_t *buf) { + struct per_thread_data { + uint8_t ____[dh.per_thread_scratch]; + }__attribute__((packed)) *data; + struct eu_state *eu; + int mem_tid, mem_euid, i; + + data = (struct per_thread_data *)buf; + for(i = 0; i < eu_info->num_threads; i++) { + eu = (struct eu_state *)&data[i]; + mem_tid = eu->sr0 & 0x7; + mem_euid = (eu->sr0 >> 8) & 0xf; + if (mem_tid == eu_tid(bit) && mem_euid == eu_id(bit)) + break; + eu = NULL; + } + + return eu; +} + +#define GRF_CMP(a, b) memcmp(a, b, sizeof(grf)) +#define GRF_CPY(a, b) memcpy(a, b, sizeof(grf)) +static int +verify(struct eu_state *eu) { + if (GRF_CMP(eu->version, protocol_version)) { + if (debug) { + printf("Bad EU protocol version %x %x\n", + ((uint32_t *)&eu->version)[0], + DEBUG_PROTOCOL_VERSION); + dump_debug((void *)eu, sizeof(*eu)); + } + return -EBAD_PROTOCOL; + } + + if (GRF_CMP(eu->state_magic, eu_msg)) { + if (debug) { + printf("Bad EU state magic %x %x\n", + ((uint32_t *)&eu->state_magic)[0], + ((uint32_t *)&eu->state_magic)[1]); + dump_debug((void *)eu, sizeof(*eu)); + } + return -EBAD_MAGIC; + } else { + GRF_CPY(eu->state_magic, cpu_ack); + } + + eu->sr0 = RSVD_EU << 8 | RSVD_THREAD; + return 0; +} + +static int +collect_data(int bit, volatile uint8_t *buf) { + struct eu_state *eu; + ssize_t num; + int ret; + + assert(eu_id(bit) != RSVD_EU); + + if (eu_fd(bit) == -1) { + char name[128]; + sprintf(name, "dump_eu_%02d_%d.bin", eu_id(bit), eu_tid(bit)); + eu_fd(bit) = open(name, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXO); + if (eu_fd(bit) == -1) + return -1; + } + + eu = find_eu_shmem(bit, buf); + + if (eu == NULL) { + if (debug) + printf("Bad offset %d %d\n", eu_id(bit), eu_tid(bit)); + return -EBAD_SHMEM; + } + + ret = verify(eu); + if (ret) + return ret; + + num = write(eu_fd(bit), (void *)eu, sizeof(*eu)); + if (num != sizeof(*eu)) { + perror("unhandled write failure"); + return EBAD_WRITE; + } + + + return 0; +} + +static void +clear_attn(int bit) { +#if 0 +/* + * This works but doesn't allow for easily changed clearing bits + */ +static void +clear_attn_old(int bit) { + int bit_to_clear = bit % 32; + bit_to_clear = 31 - bit_to_clear; + intel_register_write(0x7830 + (bit/32) * 4, 0); + intel_register_write(0x7830 + (bit/32) * 4, 1 << bit_to_clear); +} +#else + if (!force_clear) { + int bit_to_clear; + bit_to_clear = eu_info->debuggees[bit].clr; + intel_register_write(EU_ATT_CLR + (bit/32) * 4, 0); + intel_register_write(EU_ATT_CLR + (bit/32) * 4, 1 << bit_to_clear); + } else { + intel_register_write(EU_ATT_CLR + 0, 0); + intel_register_write(EU_ATT_CLR + 4, 0); + intel_register_write(EU_ATT_CLR + 0, 0xffffffff); + intel_register_write(EU_ATT_CLR + 4, 0xffffffff); + } +#endif +} + +static void +db_shutdown(int sig) { + shutting_down = 1; + printf("Shutting down...\n"); +} + +static void +die(int reason) { + int i = 0; + + intel_register_write(EU_ATT_CLR, 0); + intel_register_write(EU_ATT_CLR + 4, 0); + + if (debug_fd) + close(debug_fd); + + for (i = 0; i < eu_info->num_threads; i++) { + if (eu_info->debuggees[i].fd != -1) + close(eu_info->debuggees[i].fd); + } + + unmap_debug_buffer(); + + if (old_td_ctl) + intel_register_write(TD_CTL, old_td_ctl); + intel_register_access_fini(); + exit(reason); +} + +static int +identify_device(int devid) { + switch(devid) { + case PCI_CHIP_SANDYBRIDGE_GT1: + case PCI_CHIP_SANDYBRIDGE_M_GT1: + case PCI_CHIP_SANDYBRIDGE_S: + eu_info = >1; + break; + case PCI_CHIP_SANDYBRIDGE_GT2: + case PCI_CHIP_SANDYBRIDGE_GT2_PLUS: + case PCI_CHIP_SANDYBRIDGE_M_GT2: + case PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS: + eu_info = >2; + break; + default: + return 1; + } + + return 0; +} + +static void +parse_data(const char *file_name) { + struct eu_state *eu_state = NULL; + struct stat st; + int fd = -1; + int ret, i, elements; + + fd = open(file_name, O_RDONLY); + if (fd == -1) { + perror("open"); + goto out; + } + + ret = fstat(fd, &st); + if (ret == -1) { + perror("fstat"); + goto out; + } + + elements = st.st_size / sizeof(struct eu_state); + if (elements == 0) { + fprintf(stderr, "File not big enough for 1 entry\n"); + goto out; + } + + eu_state = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (eu_state == MAP_FAILED) { + perror("mmap"); + goto out; + } + + for(i = 0; i < elements; i++) { + printf("AIP: "); + printf("%x\n", ((uint32_t *)eu_state[i].cr0)[2]); + } +out: + if (eu_state) + munmap(eu_state, st.st_size); + if (fd != -1) + close(fd); +} + +static int +wait_for_scratch_bo(void) { + struct sockaddr_un addr; + uint32_t version; + int fd, ret, handle = -1; + + assert(sizeof(version) == sizeof(dh.version)); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) + return -1; + + /* Clean up previous runs */ + remove(SHADER_DEBUG_SOCKET); + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SHADER_DEBUG_SOCKET, sizeof(addr.sun_path) - 1); + + ret = bind(fd, (const struct sockaddr *)&addr, sizeof(addr)); + if (ret == -1) { + perror("listen"); + return -1; + } + + ret = listen(fd, 1); + if (ret == -1) { + perror("listen"); + goto done; + } + + while(1) { + int client_fd; + size_t count; + char ack[] = DEBUG_HANDSHAKE_ACK; + + client_fd = accept(fd, NULL, NULL); + if (client_fd == -1) { + perror("accept"); + goto done; + } + + count = read(client_fd, &version, sizeof(version)); + if (count != sizeof(version)) { + perror("read version"); + goto loop_out; + } + + if (version != DEBUG_HANDSHAKE_VERSION) { + fprintf(stderr, "Bad debug handshake\n"); + goto loop_out; + } + + count = read(client_fd, ((char *)&dh) + 1, sizeof(dh) - 1); + if (count != sizeof(dh) - 1) { + perror("read handshake"); + goto loop_out; + } + + count = write(client_fd, ack, sizeof(ack)); + if (count != sizeof(ack)) { + perror("write ack"); + goto loop_out; + } + handle = dh.flink_handle; + if (debug > 0) { + printf("Handshake completed successfully\n" + "\tprotocol version = %d\n" + "\tflink handle = %d\n" + "\tper thread scratch = %x\n", version, + dh.flink_handle, dh.per_thread_scratch); + } + + loop_out: + close(client_fd); + break; + } + +done: + close(fd); + return handle; +} + +static void +setup_hw_bits(void) +{ + intel_register_write(INST_PM, GEN6_GLOBAL_DEBUG_ENABLE | + GEN6_GLOBAL_DEBUG_ENABLE << 16); + old_td_ctl = intel_register_read(GEN6_TD_CTL); + intel_register_write(GEN6_TD_CTL, GEN6_TD_CTL_FORCE_TD_BKPT); +} + +int main(int argc, char* argv[]) { + struct pci_device *pci_dev; + volatile uint8_t *scratch = NULL; + int bits[64]; + int devid = -1, opt; + + while ((opt = getopt(argc, argv, "cdr:pf?h")) != -1) { + switch (opt) { + case 'c': + clear_waits = 1; + break; + case 'd': + debug = 1; + break; + case 'r': + parse_data(optarg); + exit(0); + break; + case 'p': + devid = atoi(optarg); + break; + case 'f': + force_clear = 1; + break; + case '?': + case 'h': + default: + exit(0); + } + } + + pci_dev = intel_get_pci_device(); + if (devid != -1); + devid = pci_dev->device_id; + if (identify_device(devid)) { + abort(); + } + + assert(intel_register_access_init(pci_dev, 1) == 0); + + memset(bits, -1, sizeof(bits)); + /* + * These events have to occur before the SR runs, or we need + * non-blocking versions of the functions. + */ + if (!clear_waits) { + int handle; + drm_fd = drm_open_any(); + bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096); + + setup_hw_bits(); + + /* We are probably root, make files world friendly */ + umask(0); + handle = wait_for_scratch_bo(); + if (handle == -1) { + printf("No handle from mesa, please enter manually: "); + if (fscanf(stdin, "%1d", &handle) == 0) + exit(1); + } + scratch_bo = intel_bo_gem_create_from_name(bufmgr, "scratch", handle); + if (scratch_bo == NULL) { + fprintf(stderr, "Couldn't flink buffer\n"); + abort(); + } + signal(SIGINT, db_shutdown); + printf("Press Ctrl-C to stop\n"); + } else { + int time = force_clear ? 0 : 20000; + while (wait_for_attn(time, bits)) { + clear_attn(bits[0]); + memset(bits, -1, sizeof(bits)); + } + die(0); + } + + scratch = map_debug_buffer(); + while (shutting_down == 0) { + int num_events, i; + + memset(bits, -1, sizeof(bits)); + num_events = wait_for_attn(-1, bits); + if (num_events == 0) + break; + + for (i = 0; i < num_events; i++) { + assert(bits[i] < 64 && bits[i] >= 0); + if (collect_data(bits[i], scratch)) { + bits[i] = -1; + continue; + } + clear_attn(bits[i]); + } + } + + die(0); + return 0; +} diff --git a/debugger/system_routine/.gitignore b/debugger/system_routine/.gitignore new file mode 100644 index 00000000..d19500cf --- /dev/null +++ b/debugger/system_routine/.gitignore @@ -0,0 +1,10 @@ +evict.h +eviction_macro +sr +sr.asm +sr.c +sr.cpp +tiny +tiny.asm +tiny.c +tiny.cpp diff --git a/debugger/system_routine/Makefile.am b/debugger/system_routine/Makefile.am new file mode 100644 index 00000000..2576e2aa --- /dev/null +++ b/debugger/system_routine/Makefile.am @@ -0,0 +1,42 @@ + +noinst_PROGRAMS = eviction_macro sr tiny +nodist_sr_SOURCES = sr.c +nodist_tiny_SOURCES = tiny.c + +GEN4ASM_FLAGS = -g6 -a -b +ASM_CPPFLAGS = \ + -x assembler-with-cpp \ + -P -DGEN_ASM -DSANDYBRIDGE \ + -I$(top_srcdir)/lib \ + -I$(builddir) + +evict.h : eviction_macro + $(builddir)/eviction_macro > evict.h + +sr.cpp : sr.g4a + $(srcdir)/pre_cpp.py $(srcdir)/sr.g4a > $@.tmp && mv $@.tmp $@ +sr.asm : sr.cpp evict.h + $(CPP) $(ASM_CPPFLAGS) -o $@ sr.cpp +sr.c: sr.asm + $(GEN4ASM) $(GEN4ASM_FLAGS) sr.asm -o $@ +sr.o : sr.c + $(CC) -c -o $@ sr.c +sr : sr.o + $(OBJCOPY) -O binary -K gen_eu_bytes sr.o $@ + +# Test.g4a is the simplest possible system routine we can run on the GPU +# without actually hanging the system. The system routine kernel is very +# simple and doesn't depend on any external communication to run. +tiny.cpp : test.g4a + $(srcdir)/pre_cpp.py $(srcdir)/test.g4a > $@.tmp && mv $@.tmp $@ +tiny.asm : tiny.cpp + $(CPP) $(ASM_CPPFLAGS) -o $@ tiny.cpp +tiny.c: tiny.asm + $(GEN4ASM) $(GEN4ASM_FLAGS) tiny.asm -o $@ +tiny.o : tiny.c + $(CC) -c -o $@ tiny.c +tiny : tiny.o + $(OBJCOPY) -O binary -K gen_eu_bytes tiny.o $@ + +CLEANFILES = evict.h sr.cpp sr.asm sr.c tiny.cpp tiny.asm tiny.c +EXTRA_DIST = pre_cpp.py sr.g4a test.g4a diff --git a/debugger/system_routine/eviction_macro.c b/debugger/system_routine/eviction_macro.c new file mode 100644 index 00000000..1da22332 --- /dev/null +++ b/debugger/system_routine/eviction_macro.c @@ -0,0 +1,48 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#include <stdio.h> + +#define START 0x100 +#define END ((128 << 10) / 4) + +int main(int argc, char *argv[]) { + int i; + printf("#ifdef SANDYBRIDGE\n"); + printf("#define EVICT_CACHE \\\n"); + printf("\tmov (1) m0.5:ud g0.5:ud FLAGS; \\\n"); + for (i = START; i < END - 8; i+=0x8) { + printf("\tmov (1) m0.2:ud 0x%04x:ud FLAGS; \\\n", i); + printf("\tWRITE_SCRATCH4(m0); \\\n"); + } + + printf("\tmov (1) m0.2:ud 0x%04x:ud FLAGS; \\\n", i); + printf("\tWRITE_SCRATCH4(m0)\n"); + printf("#else\n"); + printf("#define EVICT_CACHE\n"); + printf("#endif\n"); +} diff --git a/debugger/system_routine/pre_cpp.py b/debugger/system_routine/pre_cpp.py new file mode 100755 index 00000000..effea0e2 --- /dev/null +++ b/debugger/system_routine/pre_cpp.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 + +# Copyright © 2011 Intel Corporation +# +# 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 +# AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + +#very limited C-like preprocessor + +#limitations: +# no macro substitutions +# no multiline definitions +# divide operator is // + +import sys,re + +file = open(sys.argv[1], "r") + +lines = file.readlines() +len(lines) +out = dict() +defines = dict() + +count = 0 +#create a dict for our output +for line in lines: + out[count] = line + count = count + 1 + +#done is considered #define <name> <number> +def is_done(string): + m = re.match("#define\s+(\w+?)\s+([a-fA-F0-9\-]+?)\s*$", string) + return m + +#skip macros, the real cpp will handle it +def skip(string): + #macro + m = re.match("#define\s+\w+\(.+", string) + return m != None + +#put contants which are done being evaluated into the dictionary +def easy_constants(): + ret = 0 + for lineno, string in out.items(): + if skip(string): + continue + m = is_done(string) + if m != None: + key = m.group(1) + value = m.group(2) + if not key in defines: + defines[key] = int(eval(value)) + ret = 1 + return ret + +#replace names with dictionary values +def simple_replace(): + ret = 0 + for lineno, string in out.items(): + if skip(string): + continue + for key, value in defines.items(): + if is_done(string): + continue + s = re.subn(key, repr(value), string) + if s[1] > 0: + out[lineno] = s[0] + ret = s[1] + return ret + +#evaluate expressions to try to simplify them +def collapse_constants(): + ret = 0 + for lineno, string in out.items(): + if skip(string): + continue + if is_done(string): + continue + m = re.match("#define\s+(.+?)\s+(.+)$", string) + if m != None: + try: + out[lineno] = "#define " + m.group(1) + " " + repr(eval(m.group(2))) + ret = 1 + except NameError as ne: + #this happens before a variable is resolved in simple_replace + continue + except SyntaxError: + #this happens with something like #define foo bar, which the + #regular cpp can handle + continue + except: + raise KeyboardInterrupt + return ret; + +while True: + ret = 0 + ret += easy_constants() + ret += simple_replace() + ret += collapse_constants() + if ret == 0: + break; + +for lineno, string in out.items(): + print(string.rstrip()) diff --git a/debugger/system_routine/sr.g4a b/debugger/system_routine/sr.g4a new file mode 100644 index 00000000..a70e7712 --- /dev/null +++ b/debugger/system_routine/sr.g4a @@ -0,0 +1,277 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#include "debug.h" +#include "evict.h" + +#define CR0_0_ME_STATE_CTRL (1 << 31) +#define CR0_0_BP_SUPPRESS (1 << 15) +#define CR0_0_SPF_EN (1 << 2) +#define CR0_0_ACC_DIS (1 << 1) +#define CR0_1_BES_CTRL (1 << 31) +#define CR0_1_HALT_CTRL (1 << 30) +#define CR0_1_SOFT_EXCEPTION_CTRL (1 << 29) +#define CR0_1_ILLGL_OP_STS (1 << 28) +#define CR0_1_STACK_OVRFLW_STS (1 << 27) + +#define CR0_0_ENTRY_UNMASK (CR0_0_SPF_EN | CR0_0_ACC_DIS) +// TODO: Need to fix this for non breakpoint case +#define CR0_1_ENTRY_UNMASK ~(CR0_1_BES_CTRL) +#define CR0_0_RETURN_MASK ~(CR0_0_ME_STATE_CTRL | CR0_0_SPF_EN | CR0_0_ACC_DIS) + +// TODO: not sure how to make this not hardcoded +#define PER_THREAD_SCRATCH_SIZE (1 << 20) +#define PER_THREAD_QWORDS (PER_THREAD_SCRATCH_SIZE >> 4) + +/* Should get this from brw_defines.h */ +#define BRW_DATAPORT_OWORD_BLOCK_2_OWORDS 2 +#define BRW_DATAPORT_OWORD_BLOCK_4_OWORDS 3 +#define BRW_DATAPORT_OWORD_BLOCK_8_OWORDS 4 +#define GEN6_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE 8 +#define BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ 0 + +/* desc field, ie. dword3 6.3.66.2 and 2.11.2.1.4 */ +#define SEND_MLEN_5 (5<<25) +#define SEND_MLEN_3 (3<<25) +#define SEND_MLEN_2 (2<<25) +#define SEND_MLEN_1 (1<<25) +#define SEND_RLEN_1 (1<<20) +#define SEND_RLEN_0 (0<<20) +#define SEND_HEADER_PRESENT (1<<19) +#define SEND_WRITE_COMMIT (1<<17) +#define SEND_TYPE_WRITE (GEN6_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE<<13) +#define SEND_TYPE_READ (BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ<<13) +#define SEND_BLOCK_SIZE1 (BRW_DATAPORT_OWORD_BLOCK_2_OWORDS<<8) +#define SEND_BLOCK_SIZE2 (BRW_DATAPORT_OWORD_BLOCK_4_OWORDS<<8) +#define SEND_BLOCK_SIZE4 (BRW_DATAPORT_OWORD_BLOCK_8_OWORDS<<8) +#define SEND_BINDING_TABLE (255<<0) +// No write commit +#define WRITE_DESC1_XXX SEND_BINDING_TABLE | SEND_BLOCK_SIZE1 | SEND_TYPE_WRITE | SEND_HEADER_PRESENT | SEND_MLEN_2 +#define WRITE_DESC1_WC SEND_BINDING_TABLE | SEND_BLOCK_SIZE1 | SEND_TYPE_WRITE | SEND_HEADER_PRESENT | SEND_MLEN_2 | SEND_WRITE_COMMIT +#define WRITE_DESC2 SEND_BINDING_TABLE | SEND_BLOCK_SIZE2 | SEND_TYPE_WRITE | SEND_HEADER_PRESENT | SEND_MLEN_3 +#define WRITE_DESC4 SEND_BINDING_TABLE | SEND_BLOCK_SIZE4 | SEND_TYPE_WRITE | SEND_HEADER_PRESENT | SEND_MLEN_5 +#define RECV_DESC1 SEND_BINDING_TABLE | SEND_BLOCK_SIZE1 | SEND_TYPE_READ | SEND_HEADER_PRESENT | SEND_MLEN_1 | SEND_RLEN_1 +//#define SEND_DESC1 0x40902FF +#define SEND_DESC1_WC 0x40b02FF + +/* ex_desc field 6.3.66.2 */ +#define SEND_DP_RENDER_CACHE (5<<0) +#define SEND_EOT (1<<5) +#define SEND_EX_DESC SEND_DP_RENDER_CACHE + +/** + * WRITE_SCRATCH1 - Write 2 owords. + * cdst.2 - offset + * cdst.5 - per thread scratch base, relative to gsba?? + * cdst+1 - data to be written. + */ +#define WRITE_SCRATCH1(cdst) \ + send (16) null cdst SEND_EX_DESC WRITE_DESC1_XXX FLAGS +#define WRITE_SCRATCH1_WC(cdst) \ + send (16) g1 cdst SEND_EX_DESC WRITE_DESC1_WC FLAGS +#define WRITE_SCRATCH2(cdst) \ + send (16) null cdst SEND_EX_DESC WRITE_DESC2 FLAGS +#define WRITE_SCRATCH4(cdst) \ + send (16) null cdst SEND_EX_DESC WRITE_DESC4 FLAGS + +/** + * READ_SCRATCH1 - Read 2 owords. + * cdst.2 - offset + * cdst.5 - per thread scratch base, relative to gsba?? + * grf - register where read data is populated. + */ +#define READ_SCRATCH1(grf, cdst) \ + send (16) grf:ud cdst SEND_EX_DESC RECV_DESC1 FLAGS + +/** + * SET_OFFSET - setup mrf for the given offset prior to a send instruction. + * mrf - message register to be used as the header. + * offset - offset. + * + * If a WRITE_SCRATCH follows, mrf+1 -> mrf+1+n should contain the data to be + * written. + */ +#define SET_OFFSET(mrf, offset) \ + mov (1) mrf.5:ud g0.5:ud FLAGS; \ + mov (1) mrf.2:ud offset:ud FLAGS + +/** + * SAVE_CRF - save the control register + * clobbers: m0.2, m0.5 + */ +#define CR_OFFSET 0x40 +#define SAVE_CRF \ + SET_OFFSET(m0, CR_OFFSET); \ + mov (8) m1:ud 0xdeadbeef:ud FLAGS; \ + mov (1) m1.0:ud cr0.0 FLAGS; \ + mov (1) m1.1:ud cr0.1 FLAGS; \ + mov (1) m1.2:ud cr0.2 FLAGS; \ + mov (1) m1.3:ud sr0:ud FLAGS; \ + WRITE_SCRATCH1(m0) + +/* + * clobbers: m0.2, m0.5 + */ +#define STORE_GRF(grf, offset) \ + SET_OFFSET(m0, offset); \ + mov (8) m1:ud grf:ud FLAGS; \ + WRITE_SCRATCH1(m0) + +/* + * clobbers: m0.2, m0.5 + */ +#define LOAD_GRF(grf, offset) \ + SET_OFFSET(m0, offset); \ + READ_SCRATCH1(grf, m0) + +/* + * clobbers: mrf.2 mrf.5 + */ +#define STORE_MRF(mrf, offset) \ + SET_OFFSET(mrf, offset); \ + WRITE_SCRATCH1(mrf) + +/* + * non-quirky semantics, unlike STORE_MRF + * clobbers: g1 + */ +#define LOAD_MRF(mrf, offset) \ + LOAD_GRF(g1, offset); \ + mov (8) mrf:ud g1:ud FLAGS + +#define SAVE_ALL_MRF \ + /* m1 is saved already */ \ + STORE_MRF(m1, 0x2); \ + STORE_MRF(m2, 0x4); \ + STORE_MRF(m3, 0x6); \ + STORE_MRF(m4, 0x8); \ + STORE_MRF(m5, 0xa); \ + STORE_MRF(m6, 0xc); \ + STORE_MRF(m7, 0xe); \ + STORE_MRF(m8, 0x10); \ + STORE_MRF(m9, 0x12); \ + STORE_MRF(m10, 0x14); \ + STORE_MRF(m11, 0x16); \ + STORE_MRF(m12, 0x18); \ + STORE_MRF(m13, 0x1a); \ + STORE_MRF(m14, 0x1c) + +#define RESTORE_ALL_MRF \ + LOAD_MRF(m15, 0x1c); \ + LOAD_MRF(m14, 0x1a); \ + LOAD_MRF(m13, 0x18); \ + LOAD_MRF(m12, 0x16); \ + LOAD_MRF(m11, 0x14); \ + LOAD_MRF(m10, 0x12); \ + LOAD_MRF(m9, 0x10); \ + LOAD_MRF(m8, 0xe); \ + LOAD_MRF(m7, 0xc); \ + LOAD_MRF(m6, 0xa); \ + LOAD_MRF(m5, 0x8); \ + LOAD_MRF(m4, 0x6); \ + LOAD_MRF(m3, 0x4); \ + LOAD_MRF(m2, 0x2); \ + LOAD_MRF(m1, 0x0) + +#ifndef SANDYBRIDGE + #error Only SandyBridge is supported +#endif + +/* Default flags for an instruction */ +#define FLAGS { ALIGN1, SWITCH, MASK_DISABLE, ACCWRCTRL} + +/* + * We can clobber m0, and g0.4, everything else must be saved. + */ +Enter: + nop; + + or (1) cr0.0 cr0.0 CR0_0_ENTRY_UNMASK:ud FLAGS; + + /* + * g0.5 has the per thread scratch space when running in FS or VS. + * If we don't have a valid g0.5, we can calculate a per thread scratch offset + * using the system registers. The problem is we do not have a good way to know + * the offset from GSBA. The system routine will have to be hardcoded or + * dynamically patched with the correct offset. + * TID is in sr0.0[2:0] + * EUID is in sr0.0[11:8] + */ + +#ifdef GPGPU + mov (1) g0.4:ud 0:ud FLAGS; +#if 0 + /* This should work according to the docs, the add blows up */ + shr (1) g0.8:uw sr0.0:uw 5 FLAGS; + add (1) g0.16:ub gr0.16:ub sr0.0:ub FLAGS; +#else + shr (1) g0.8:uw sr0.0:uw 5 FLAGS; + mov (1) g0.9:uw sr0.0:uw FLAGS; + and (1) g0.9:uw g0.9:uw 0x7:uw FLAGS; + add (1) g0.8:uw g0.8:uw g0.9:uw FLAGS; + mov (1) g0.9:uw 0:uw FLAGS; + mul (1) g0.4:ud g0.4:ud PER_THREAD_QWORDS FLAGS; +#endif +#endif + + mov (8) m0:ud 0:ud FLAGS; + + /* Saves must occur in order so as not to clobber the next register */ + STORE_MRF(m0, 0); + STORE_GRF(g0, 0x20); + STORE_GRF(g1, 0x22); + SAVE_ALL_MRF; + + mov (8) g1:ud STATE_EU_MSG:ud FLAGS; + STORE_GRF(g1, STATE_QWORD); + + mov (8) g1:ud DEBUG_PROTOCOL_VERSION:ud FLAGS; + STORE_GRF(g1, COMMUNICATION_QWORD); + + SAVE_CRF; + + EVICT_CACHE; + wait n1:ud; + EVICT_CACHE; + + /* Using this to try to keep coherency */ + LOAD_GRF(g1, CR_OFFSET); + LOAD_GRF(g1, COMMUNICATION_QWORD); + LOAD_GRF(g1, STATE_QWORD); + + RESTORE_ALL_MRF; + LOAD_GRF(g1, 0x22); + LOAD_GRF(g0, 0x20); + + /* Clear breakpoint status */ + and (1) cr0.1 cr0.1 CR0_1_ENTRY_UNMASK:ud FLAGS; + + /* set breakpoint suppress this should be conditional on bes */ + or (1) cr0.0 cr0.0 CR0_0_BP_SUPPRESS:ud FLAGS; + + and (1) cr0.0 cr0.0 CR0_0_RETURN_MASK:ud FLAGS; + nop; diff --git a/debugger/system_routine/test.g4a b/debugger/system_routine/test.g4a new file mode 100644 index 00000000..e4296e01 --- /dev/null +++ b/debugger/system_routine/test.g4a @@ -0,0 +1,64 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#include "debug.h" + +#define CR0_0_ME_STATE_CTRL (1 << 31) +#define CR0_0_BP_SUPPRESS (1 << 15) +#define CR0_0_SPF_EN (1 << 2) +#define CR0_0_ACC_DIS (1 << 1) +#define CR0_1_BES_CTRL (1 << 31) +#define CR0_1_HALT_CTRL (1 << 30) +#define CR0_1_SOFT_EXCEPTION_CTRL (1 << 29) +#define CR0_1_ILLGL_OP_STS (1 << 28) +#define CR0_1_STACK_OVRFLW_STS (1 << 27) + +#define CR0_0_ENTRY_UNMASK (CR0_0_SPF_EN | CR0_0_ACC_DIS) +// TODO: Need to fix this for non breakpoint case +#define CR0_1_ENTRY_UNMASK ~(CR0_1_BES_CTRL) +#define CR0_0_RETURN_MASK ~(CR0_0_ME_STATE_CTRL | CR0_0_SPF_EN | CR0_0_ACC_DIS) + +#ifndef SANDYBRIDGE + #error Only SandyBridge is supported +#endif + +/* Default flags for an instruction */ +#define FLAGS { ALIGN1, SWITCH, MASK_DISABLE, ACCWRCTRL} + +Enter: + nop; + + or (1) cr0.0 cr0.0 CR0_0_ENTRY_UNMASK:ud FLAGS; + + /* Clear breakpoint status */ + and (1) cr0.1 cr0.1 CR0_1_ENTRY_UNMASK:ud FLAGS; + + /* set breakpoint suppress this should be conditional on bes */ + or (1) cr0.0 cr0.0 CR0_0_BP_SUPPRESS:ud FLAGS; + + and (1) cr0.0 cr0.0 CR0_0_RETURN_MASK:ud FLAGS; + nop; diff --git a/demos/.gitignore b/demos/.gitignore new file mode 100644 index 00000000..cd80b0b5 --- /dev/null +++ b/demos/.gitignore @@ -0,0 +1 @@ +intel_sprite_on diff --git a/demos/Makefile.am b/demos/Makefile.am new file mode 100644 index 00000000..49804d79 --- /dev/null +++ b/demos/Makefile.am @@ -0,0 +1,7 @@ +bin_PROGRAMS = \ + intel_sprite_on \ + $(NULL) + +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib +AM_CFLAGS = $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) +LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) diff --git a/demos/intel_sprite_on.c b/demos/intel_sprite_on.c new file mode 100644 index 00000000..c1d02245 --- /dev/null +++ b/demos/intel_sprite_on.c @@ -0,0 +1,1068 @@ +/* + * Copyright 2012 Corporation + * + * Author: + * Armin Reese <armin.c.reese@intel.com> + * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS 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. + */ + +/* + * This program is intended for testing sprite functionality. + */ +#include <assert.h> +#include <errno.h> +#include <math.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <termios.h> +#include <sys/time.h> +#include <sys/poll.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/ioctl.h> + +#include "i915_drm.h" +#include "drmtest.h" + +#if defined(DRM_IOCTL_MODE_ADDFB2) && defined(DRM_I915_SET_SPRITE_COLORKEY) +#define TEST_PLANES 1 +#include "drm_fourcc.h" +#endif + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct type_name +{ + int type; + const char *name; +}; + +#define type_name_fn(res) \ +static const char * res##_str(int type) { \ + unsigned int i; \ + for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ + if (res##_names[i].type == type) \ + return res##_names[i].name; \ + } \ + return "(invalid)"; \ +} + +struct type_name encoder_type_names[] = { + { DRM_MODE_ENCODER_NONE, "none" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, +}; + +type_name_fn(encoder_type) + +struct type_name connector_status_names[] = { + { DRM_MODE_CONNECTED, "connected" }, + { DRM_MODE_DISCONNECTED, "disconnected" }, + { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, +}; + +type_name_fn(connector_status) + +struct type_name connector_type_names[] = { + { DRM_MODE_CONNECTOR_Unknown, "unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, + { DRM_MODE_CONNECTOR_TV, "TV" }, + { DRM_MODE_CONNECTOR_eDP, "Embedded DisplayPort" }, +}; + +type_name_fn(connector_type) + +/* + * Mode setting with the kernel interfaces is a bit of a chore. + * First you have to find the connector in question and make sure the + * requested mode is available. + * Then you need to find the encoder attached to that connector so you + * can bind it with a free crtc. + */ +struct connector +{ + uint32_t id; + int mode_valid; + drmModeModeInfo mode; + drmModeEncoder *encoder; + drmModeConnector *connector; + int crtc; + int pipe; +}; + +static void dump_mode( + drmModeModeInfo *mode) +{ + printf(" %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d\n", + mode->name, + mode->vrefresh, + mode->hdisplay, + mode->hsync_start, + mode->hsync_end, + mode->htotal, + mode->vdisplay, + mode->vsync_start, + mode->vsync_end, + mode->vtotal, + mode->flags, + mode->type, + mode->clock); +} + +static void dump_connectors( + int gfx_fd, + drmModeRes *resources) +{ + int i, j; + + printf("Connectors:\n"); + printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n"); + for (i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(gfx_fd, resources->connectors[i]); + if (!connector) { + printf("could not get connector %i: %s\n", + resources->connectors[i], strerror(errno)); + continue; + } + + printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n", + connector->connector_id, + connector->encoder_id, + connector_status_str(connector->connection), + connector_type_str(connector->connector_type), + connector->mmWidth, connector->mmHeight, + connector->count_modes); + + if (!connector->count_modes) + continue; + + printf(" modes:\n"); + printf(" name refresh (Hz) hdisp hss hse htot vdisp " + "vss vse vtot flags type clock\n"); + for (j = 0; j < connector->count_modes; j++) + dump_mode(&connector->modes[j]); + + drmModeFreeConnector(connector); + } + printf("\n"); +} + +static void dump_crtcs( + int gfx_fd, + drmModeRes *resources) +{ + int i; + + printf("CRTCs:\n"); + printf("id\tfb\tpos\tsize\n"); + for (i = 0; i < resources->count_crtcs; i++) { + drmModeCrtc *crtc; + + crtc = drmModeGetCrtc(gfx_fd, resources->crtcs[i]); + if (!crtc) { + printf("could not get crtc %i: %s\n", + resources->crtcs[i], + strerror(errno)); + continue; + } + printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", + crtc->crtc_id, + crtc->buffer_id, + crtc->x, crtc->y, + crtc->width, crtc->height); + dump_mode(&crtc->mode); + + drmModeFreeCrtc(crtc); + } + printf("\n"); +} + +static void dump_planes( + int gfx_fd, + drmModeRes *resources) +{ + drmModePlaneRes *plane_resources; + drmModePlane *ovr; + int i; + + plane_resources = drmModeGetPlaneResources(gfx_fd); + if (!plane_resources) { + printf("drmModeGetPlaneResources failed: %s\n", + strerror(errno)); + return; + } + + printf("Planes:\n"); + printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\n"); + for (i = 0; i < plane_resources->count_planes; i++) { + ovr = drmModeGetPlane(gfx_fd, plane_resources->planes[i]); + if (!ovr) { + printf("drmModeGetPlane failed: %s\n", + strerror(errno)); + continue; + } + + printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%d\n", + ovr->plane_id, ovr->crtc_id, ovr->fb_id, + ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, + ovr->gamma_size); + + drmModeFreePlane(ovr); + } + printf("\n"); + + return; +} + +static void connector_find_preferred_mode( + int gfx_fd, + drmModeRes *gfx_resources, + struct connector *c) +{ + drmModeConnector *connector; + drmModeEncoder *encoder = NULL; + int i, j; + + /* First, find the connector & mode */ + c->mode_valid = 0; + connector = drmModeGetConnector(gfx_fd, c->id); + if (!connector) { + printf("could not get connector %d: %s\n", + c->id, + strerror(errno)); + drmModeFreeConnector(connector); + return; + } + + if (connector->connection != DRM_MODE_CONNECTED) { + drmModeFreeConnector(connector); + return; + } + + if (!connector->count_modes) { + printf("connector %d has no modes\n", + c->id); + drmModeFreeConnector(connector); + return; + } + + if (connector->connector_id != c->id) { + printf("connector id doesn't match (%d != %d)\n", + connector->connector_id, + c->id); + drmModeFreeConnector(connector); + return; + } + + for (j = 0; j < connector->count_modes; j++) { + c->mode = connector->modes[j]; + if (c->mode.type & DRM_MODE_TYPE_PREFERRED) { + c->mode_valid = 1; + break; + } + } + + if (!c->mode_valid) { + if (connector->count_modes > 0) { + /* use the first mode as test mode */ + c->mode = connector->modes[0]; + c->mode_valid = 1; + } else { + printf("failed to find any modes on connector %d\n", + c->id); + return; + } + } + + /* Now get the encoder */ + for (i = 0; i < connector->count_encoders; i++) { + encoder = drmModeGetEncoder(gfx_fd, connector->encoders[i]); + + if (!encoder) { + printf("could not get encoder %i: %s\n", + gfx_resources->encoders[i], + strerror(errno)); + drmModeFreeEncoder(encoder); + continue; + } + + break; + } + + c->encoder = encoder; + + if (i == gfx_resources->count_encoders) { + printf("failed to find encoder\n"); + c->mode_valid = 0; + return; + } + + /* Find first CRTC not in use */ + for (i = 0; i < gfx_resources->count_crtcs; i++) { + if (gfx_resources->crtcs[i] && (c->encoder->possible_crtcs & (1<<i))) + break; + } + c->crtc = gfx_resources->crtcs[i]; + c->pipe = i; + + gfx_resources->crtcs[i] = 0; + + c->connector = connector; +} + +static int connector_find_plane(int gfx_fd, struct connector *c) +{ + drmModePlaneRes *plane_resources; + drmModePlane *ovr; + uint32_t id = 0; + int i; + + plane_resources = drmModeGetPlaneResources(gfx_fd); + if (!plane_resources) { + printf("drmModeGetPlaneResources failed: %s\n", + strerror(errno)); + return 0; + } + + for (i = 0; i < plane_resources->count_planes; i++) { + ovr = drmModeGetPlane(gfx_fd, plane_resources->planes[i]); + if (!ovr) { + printf("drmModeGetPlane failed: %s\n", + strerror(errno)); + continue; + } + + if (ovr->possible_crtcs & (1 << c->pipe)) { + id = ovr->plane_id; + drmModeFreePlane(ovr); + break; + } + drmModeFreePlane(ovr); + } + + return id; +} + +static int prepare_primary_surface( + int fd, + int prim_width, + int prim_height, + uint32_t *prim_handle, + uint32_t *prim_stride, + uint32_t *prim_size, + int tiled) +{ + uint32_t bytes_per_pixel = sizeof(uint32_t); + uint32_t *prim_fb_ptr; + struct drm_i915_gem_set_tiling set_tiling; + + if (bytes_per_pixel != sizeof(uint32_t)) { + printf("Bad bytes_per_pixel for primary surface: %d\n", + bytes_per_pixel); + return -EINVAL; + } + + if (tiled) { + int v; + + /* Round the tiling up to the next power-of-two and the + * region up to the next pot fence size so that this works + * on all generations. + * + * This can still fail if the framebuffer is too large to + * be tiled. But then that failure is expected. + */ + + v = prim_width * bytes_per_pixel; + for (*prim_stride = 512; *prim_stride < v; *prim_stride *= 2) + ; + + v = *prim_stride * prim_height; + for (*prim_size = 1024*1024; *prim_size < v; *prim_size *= 2) + ; + } else { + /* Scan-out has a 64 byte alignment restriction */ + *prim_stride = (prim_width * bytes_per_pixel + 63) & ~63; + *prim_size = *prim_stride * prim_height; + } + + *prim_handle = gem_create(fd, *prim_size); + + if (tiled) { + set_tiling.handle = *prim_handle; + set_tiling.tiling_mode = I915_TILING_X; + set_tiling.stride = *prim_stride; + if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling)) { + printf("Set tiling failed: %s (stride=%d, size=%d)\n", + strerror(errno), *prim_stride, *prim_size); + return -1; + } + } + + prim_fb_ptr = gem_mmap(fd, + *prim_handle, *prim_size, + PROT_READ | PROT_WRITE); + + if (prim_fb_ptr != NULL) { + // Write primary surface with gray background + memset(prim_fb_ptr, 0x3f, *prim_size); + munmap(prim_fb_ptr, *prim_size); + } + + return 0; +} + +static void fill_sprite( + int sprite_width, + int sprite_height, + int sprite_stride, + int sprite_index, + void *sprite_fb_ptr) +{ + __u32 *pLinePat0, + *pLinePat1, + *pLinePtr; + int i, + line; + int stripe_width; + + stripe_width = ((sprite_width > 64) && + (sprite_height > 64)) ? (sprite_index + 1) * 8 : + (sprite_index + 1) * 2; + + // Note: sprite_stride is in bytes. pLinePat0 and pLinePat1 + // are both __u32 pointers + pLinePat0 = sprite_fb_ptr; + pLinePat1 = pLinePat0 + (stripe_width * (sprite_stride / sizeof(*pLinePat0))); + + for (i = 0; i < sprite_width; i++) { + *(pLinePat0 + i) = ((i / stripe_width) & 0x1) ? 0 : ~0; + *(pLinePat1 + i) = ~(*(pLinePat0 + i)); + } + + for (line = 1; line < sprite_height; line++) { + if (line == stripe_width) { + continue; + } + + pLinePtr = ((line / stripe_width) & 0x1) ? pLinePat1 : pLinePat0; + memcpy( pLinePat0 + ((sprite_stride / sizeof(*pLinePat0)) * line), + pLinePtr, + sprite_width * sizeof(*pLinePat0)); + } + + return; +} + +static int prepare_sprite_surfaces( + int fd, + int sprite_width, + int sprite_height, + uint32_t num_surfaces, + uint32_t *sprite_handles, + uint32_t *sprite_stride, + uint32_t *sprite_size, + int tiled) +{ + uint32_t bytes_per_pixel = sizeof(uint32_t); + uint32_t *sprite_fb_ptr; + struct drm_i915_gem_set_tiling set_tiling; + int i; + + if (bytes_per_pixel != sizeof(uint32_t)) { + printf("Bad bytes_per_pixel for sprite: %d\n", bytes_per_pixel); + return -EINVAL; + } + + if (tiled) { + int v; + + /* Round the tiling up to the next power-of-two and the + * region up to the next pot fence size so that this works + * on all generations. + * + * This can still fail if the framebuffer is too large to + * be tiled. But then that failure is expected. + */ + + v = sprite_width * bytes_per_pixel; + for (*sprite_stride = 512; *sprite_stride < v; *sprite_stride *= 2) + ; + + v = *sprite_stride * sprite_height; + for (*sprite_size = 1024*1024; *sprite_size < v; *sprite_size *= 2) + ; + } else { + /* Scan-out has a 64 byte alignment restriction */ + *sprite_stride = (sprite_width * bytes_per_pixel + 63) & ~63; + *sprite_size = *sprite_stride * sprite_height; + } + + for (i = 0; i < num_surfaces; i++) { + // Create the sprite surface + sprite_handles[i] = gem_create(fd, *sprite_size); + + if (tiled) { + set_tiling.handle = sprite_handles[i]; + set_tiling.tiling_mode = I915_TILING_X; + set_tiling.stride = *sprite_stride; + if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling)) { + printf("Set tiling failed: %s (stride=%d, size=%d)\n", + strerror(errno), *sprite_stride, *sprite_size); + return -1; + } + } + + // Get pointer to the surface + sprite_fb_ptr = gem_mmap(fd, + sprite_handles[i], *sprite_size, + PROT_READ | PROT_WRITE); + + if (sprite_fb_ptr != NULL) { + // Fill with checkerboard pattern + fill_sprite( + sprite_width, + sprite_height, + *sprite_stride, + i, sprite_fb_ptr); + + munmap(sprite_fb_ptr, *sprite_size); + } else { + i--; + while (i >= 0) { + gem_close(fd, sprite_handles[i]); + i--; + } + } + } + + return 0; +} + +static void ricochet( + int tiled, + int sprite_w, + int sprite_h, + int out_w, + int out_h, + int dump_info) +{ + int ret; + int gfx_fd; + int keep_moving; + const int num_surfaces = 3; + uint32_t sprite_handles[num_surfaces]; + uint32_t sprite_fb_id[num_surfaces]; + int sprite_x; + int sprite_y; + uint32_t sprite_stride; + uint32_t sprite_size; + uint32_t handles[4], + pitches[4], + offsets[4]; /* we only use [0] */ + uint32_t prim_width, + prim_height, + prim_handle, + prim_stride, + prim_size, + prim_fb_id; + struct drm_intel_sprite_colorkey set; + struct connector curr_connector; + drmModeRes *gfx_resources; + struct termios orig_term, + curr_term; + int c_index; + int sprite_index; + unsigned int sprite_plane_id; + uint32_t plane_flags = 0; + int delta_x, + delta_y; + struct timeval stTimeVal; + long long currTime, + prevFlipTime, + prevMoveTime, + deltaFlipTime, + deltaMoveTime, + SleepTime; + char key; + + // Open up I915 graphics device + gfx_fd = drmOpen("i915", NULL); + if (gfx_fd < 0) { + printf("Failed to load i915 driver: %s\n", strerror(errno)); + return; + } + + // Obtain pointer to struct containing graphics resources + gfx_resources = drmModeGetResources(gfx_fd); + if (!gfx_resources) { + printf("drmModeGetResources failed: %s\n", strerror(errno)); + return; + } + + if (dump_info != 0) { + dump_connectors(gfx_fd, gfx_resources); + dump_crtcs(gfx_fd, gfx_resources); + dump_planes(gfx_fd, gfx_resources); + } + + // Save previous terminal settings + if (tcgetattr( 0, &orig_term) != 0) { + printf("tcgetattr failure: %s\n", + strerror(errno)); + return; + } + + // Set up input to return characters immediately + curr_term = orig_term; + curr_term.c_lflag &= ~(ICANON | ECHO | ECHONL); + curr_term.c_cc[VMIN] = 0; // No minimum number of characters + curr_term.c_cc[VTIME] = 0 ; // Return immediately, even if + // nothing has been entered. + if (tcsetattr( 0, TCSANOW, &curr_term) != 0) { + printf("tcgetattr failure: %s\n", + strerror(errno)); + return; + } + + // Cycle through all connectors and display the flying sprite + // where there are displays attached and the hardware will support it. + for (c_index = 0; c_index < gfx_resources->count_connectors; c_index++) { + curr_connector.id = gfx_resources->connectors[c_index]; + + // Find the native (preferred) display mode + connector_find_preferred_mode(gfx_fd, gfx_resources, &curr_connector); + if (curr_connector.mode_valid == 0) { + printf("No valid preferred mode detected\n"); + goto out; + } + + // Determine if sprite hardware is available on pipe + // associated with this connector. + sprite_plane_id = connector_find_plane(gfx_fd, &curr_connector); + if (!sprite_plane_id) { + printf("Failed to find sprite plane on crtc\n"); + goto out; + } + + // Width and height of preferred mode + prim_width = curr_connector.mode.hdisplay; + prim_height = curr_connector.mode.vdisplay; + + // Allocate and fill memory for primary surface + ret = prepare_primary_surface( + gfx_fd, + prim_width, + prim_height, + &prim_handle, + &prim_stride, + &prim_size, + tiled); + if (ret != 0) { + printf("Failed to add primary fb (%dx%d): %s\n", + prim_width, prim_height, strerror(errno)); + goto out; + } + + // Add the primary surface framebuffer + ret = drmModeAddFB( + gfx_fd, + prim_width, + prim_height, + 24, 32, + prim_stride, + prim_handle, + &prim_fb_id); + gem_close(gfx_fd, prim_handle); + + if (ret != 0) { + printf("Failed to add primary fb (%dx%d): %s\n", + prim_width, prim_height, strerror(errno)); + goto out; + } + + // Allocate and fill sprite surfaces + ret = prepare_sprite_surfaces( + gfx_fd, + sprite_w, + sprite_h, + num_surfaces, + &sprite_handles[0], + &sprite_stride, + &sprite_size, + tiled); + if (ret != 0) { + printf("Preparation of sprite surfaces failed %dx%d\n", + sprite_w, sprite_h); + goto out; + } + + // Add the sprite framebuffers + for (sprite_index = 0; sprite_index < num_surfaces; sprite_index++) { + handles[0] = sprite_handles[sprite_index]; + handles[1] = handles[0]; + handles[2] = handles[0]; + handles[3] = handles[0]; + pitches[0] = sprite_stride; + pitches[1] = sprite_stride; + pitches[2] = sprite_stride; + pitches[3] = sprite_stride; + memset(offsets, 0, sizeof(offsets)); + + ret = drmModeAddFB2( + gfx_fd, + sprite_w, sprite_h, DRM_FORMAT_XRGB8888, + handles, pitches, offsets, &sprite_fb_id[sprite_index], + plane_flags); + gem_close(gfx_fd, sprite_handles[sprite_index]); + + if (ret) { + printf("Failed to add sprite fb (%dx%d): %s\n", + sprite_w, sprite_h, strerror(errno)); + + sprite_index--; + while (sprite_index >= 0) { + drmModeRmFB(gfx_fd, sprite_fb_id[sprite_index]); + sprite_index--; + } + goto out; + } + } + + if (dump_info != 0) { + printf("Displayed Mode Connector struct:\n" + " .id = %d\n" + " .mode_valid = %d\n" + " .crtc = %d\n" + " .pipe = %d\n" + " drmModeModeInfo ...\n" + " .name = %s\n" + " .type = %d\n" + " .flags = %08x\n" + " drmModeEncoder ...\n" + " .encoder_id = %d\n" + " .encoder_type = %d (%s)\n" + " .crtc_id = %d\n" + " .possible_crtcs = %d\n" + " .possible_clones = %d\n" + " drmModeConnector ...\n" + " .connector_id = %d\n" + " .encoder_id = %d\n" + " .connector_type = %d (%s)\n" + " .connector_type_id = %d\n\n", + curr_connector.id, + curr_connector.mode_valid, + curr_connector.crtc, + curr_connector.pipe, + curr_connector.mode.name, + curr_connector.mode.type, + curr_connector.mode.flags, + curr_connector.encoder->encoder_id, + curr_connector.encoder->encoder_type, + encoder_type_str(curr_connector.encoder->encoder_type), + curr_connector.encoder->crtc_id, + curr_connector.encoder->possible_crtcs, + curr_connector.encoder->possible_clones, + curr_connector.connector->connector_id, + curr_connector.connector->encoder_id, + curr_connector.connector->connector_type, + connector_type_str(curr_connector.connector->connector_type), + curr_connector.connector->connector_type_id); + + printf("Sprite surface dimensions = %dx%d\n" + "Sprite output dimensions = %dx%d\n" + "Press any key to continue >\n", + sprite_w, + sprite_h, + out_w, + out_h); + + // Wait for a key-press + while( read(0, &key, 1) == 0); + // Purge unread characters + tcflush(0, TCIFLUSH); + } + + // Set up the primary display mode + ret = drmModeSetCrtc( + gfx_fd, + curr_connector.crtc, + prim_fb_id, + 0, 0, + &curr_connector.id, + 1, + &curr_connector.mode); + if (ret != 0) + { + printf("Failed to set mode (%dx%d@%dHz): %s\n", + prim_width, prim_height, curr_connector.mode.vrefresh, + strerror(errno)); + continue; + } + + // Set the sprite colorkey state + set.plane_id = sprite_plane_id; + set.min_value = 0; + set.max_value = 0; + set.flags = I915_SET_COLORKEY_NONE; + ret = drmCommandWrite(gfx_fd, DRM_I915_SET_SPRITE_COLORKEY, &set, + sizeof(set)); + + // Set up sprite output dimensions, initial position, etc. + if (out_w > prim_width / 2) + out_w = prim_width / 2; + if (out_h > prim_height / 2) + out_h = prim_height / 2; + + delta_x = 3; + delta_y = 4; + sprite_x = (prim_width / 2) - (out_w / 2); + sprite_y = (prim_height / 2) - (out_h / 2); + + currTime = 0; + prevFlipTime = 0; // Will force immediate sprite flip + prevMoveTime = 0; // Will force immediate sprite move + deltaFlipTime = 500000; // Flip sprite surface every 1/2 second + deltaMoveTime = 100000; // Move sprite every 100 ms + sprite_index = num_surfaces - 1; + keep_moving = 1; + + // Bounce sprite off the walls + while (keep_moving) { + // Obtain system time in usec. + if (gettimeofday( &stTimeVal, NULL ) != 0) { + printf("gettimeofday error: %s\n", + strerror(errno)); + } else { + currTime = ((long long)stTimeVal.tv_sec * 1000000) + stTimeVal.tv_usec; + } + + // Check if it's time to flip the sprite surface + if (currTime - prevFlipTime > deltaFlipTime) { + sprite_index = (sprite_index + 1) % num_surfaces; + + prevFlipTime = currTime; + } + + // Move the sprite on the screen and flip + // the surface if the index has changed + if (drmModeSetPlane( + gfx_fd, + sprite_plane_id, + curr_connector.crtc, + sprite_fb_id[sprite_index], + plane_flags, + sprite_x, sprite_y, + out_w, out_h, + 0, 0, + sprite_w, sprite_h)) { + printf("Failed to enable sprite plane: %s\n", + strerror(errno)); + } + + // Check if it's time to move the sprite surface + if (currTime - prevMoveTime > deltaMoveTime) { + + // Compute the next position for sprite + sprite_x += delta_x; + sprite_y += delta_y; + if (sprite_x < 0) { + sprite_x = 0; + delta_x = -delta_x; + } + else if (sprite_x > prim_width - out_w) { + sprite_x = prim_width - out_w; + delta_x = -delta_x; + } + + if (sprite_y < 0) { + sprite_y = 0; + delta_y = -delta_y; + } + else if (sprite_y > prim_height - out_h) { + sprite_y = prim_height - out_h; + delta_y = -delta_y; + } + + prevMoveTime = currTime; + } + + // Fetch a key from input (non-blocking) + if (read(0, &key, 1) == 1) { + switch (key) { + case 'q': // Kill the program + case 'Q': + goto out; + break; + case 's': // Slow down sprite movement; + deltaMoveTime = (deltaMoveTime * 100) / 90; + if (deltaMoveTime > 800000) { + deltaMoveTime = 800000; + } + break; + case 'S': // Speed up sprite movement; + deltaMoveTime = (deltaMoveTime * 100) / 110; + if (deltaMoveTime < 2000) { + deltaMoveTime = 2000; + } + break; + case 'f': // Slow down sprite flipping; + deltaFlipTime = (deltaFlipTime * 100) / 90; + if (deltaFlipTime > 1000000) { + deltaFlipTime = 1000000; + } + break; + case 'F': // Speed up sprite flipping; + deltaFlipTime = (deltaFlipTime * 100) / 110; + if (deltaFlipTime < 20000) { + deltaFlipTime = 20000; + } + break; + case 'n': // Next connector + case 'N': + keep_moving = 0; + break; + default: + break; + } + + // Purge unread characters + tcflush(0, TCIFLUSH); + } + + // Wait for min of flip or move deltas + SleepTime = (deltaFlipTime < deltaMoveTime) ? + deltaFlipTime : deltaMoveTime; + usleep(SleepTime); + } + } + +out: + // Purge unread characters + tcflush(0, TCIFLUSH); + // Restore previous terminal settings + if (tcsetattr( 0, TCSANOW, &orig_term) != 0) { + printf("tcgetattr failure: %s\n", + strerror(errno)); + return; + } + + drmModeFreeResources(gfx_resources); +} + +static void usage(char *name) +{ + printf("usage: %s -s <plane width>x<plane height> [-dhto]\n" + "\t-d\t[optional] dump mode information\n" + "\t-h\t[optional] output help message\n" + "\t-t\t[optional] enable tiling\n" + "\t-o\t[optional] <output rect width>x<output rect height>\n\n" + "Keyboard control for sprite movement and flip rate ...\n" + "\t'q' or 'Q' - Quit the program\n" + "\t'n' or 'N' - Switch to next display\n" + "\t's' - Slow sprite movement\n" + "\t'S' - Speed up sprite movement\n" + "\t'f' - Slow sprite surface flipping\n" + "\t'F' - Speed up sprite surface flipping\n", + name); +} + +int main(int argc, char **argv) +{ + int c; + int test_overlay = 0, + enable_tiling = 0, + dump_info = 0; + int plane_width = 0, + plane_height = 0, + out_width = 0, + out_height = 0; + static char optstr[] = "ds:o:th"; + + opterr = 0; + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 'd': // Dump information + dump_info = 1; + break; + case 't': // Tiling enable + enable_tiling = 1; + break; + case 's': // Surface dimensions + if (sscanf(optarg, "%dx%d", + &plane_width, &plane_height) != 2) + usage(argv[0]); + test_overlay = 1; + break; + case 'o': // Output dimensions + if (sscanf(optarg, "%dx%d", + &out_width, &out_height) != 2) + usage(argv[0]); + break; + default: + printf("unknown option %c\n", c); + /* fall through */ + case 'h': // Help! + usage(argv[0]); + goto out; + } + } + + if (test_overlay) { + if (out_width < (plane_width / 2)) { + out_width = plane_width; + } + + if (out_height < (plane_height / 2)) { + out_height = plane_height; + } + + ricochet(enable_tiling, + plane_width, + plane_height, + out_width, + out_height, + dump_info); + } else { + printf("Sprite dimensions are required:\n"); + usage(argv[0]); + } + +out: + exit(0); +} diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 00000000..d8f081fe --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,36 @@ + +noinst_LTLIBRARIES = libintel_tools.la + +AM_CPPFLAGS = -I$(top_srcdir) +AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) + +libintel_tools_la_SOURCES = \ + debug.h \ + drmtest.c \ + drmtest.h \ + i830_reg.h \ + i915_3d.h \ + i915_reg.h \ + instdone.c \ + instdone.h \ + intel_batchbuffer.c \ + intel_batchbuffer.h \ + intel_chipset.h \ + intel_drm.c \ + intel_gpu_tools.h \ + intel_mmio.c \ + intel_pci.c \ + intel_reg.h \ + rendercopy_i915.c \ + rendercopy_i830.c \ + gen6_render.h \ + gen7_render.h \ + rendercopy_gen6.c \ + rendercopy_gen7.c \ + rendercopy.h \ + intel_reg_map.c \ + intel_dpio.c \ + $(NULL) + +LDADD = $(CAIRO_LIBS) +AM_CFLAGS += $(CAIRO_CFLAGS) diff --git a/lib/debug.h b/lib/debug.h new file mode 100644 index 00000000..af9cf391 --- /dev/null +++ b/lib/debug.h @@ -0,0 +1,92 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +#define DEBUG_PROTOCOL_VERSION 1 +#define COMMUNICATION_OFFSET 0xc00 +#define COMMUNICATION_QWORD 0xc0 + +#define STATE_EU_MSG 0x47534d65 /* eMSG */ +#define STATE_CPU_ACK 0x4b434163 /* cACK */ +#define STATE_OFFSET 0xc20 +#define STATE_QWORD 0xc2 + +#define TX_OFFSET 0xc40 +#define TX_QWORD 0xc4 +#define RX_OFFSET 0xc60 +#define RX_QWORD 0xc6 + +#ifndef GEN_ASM +typedef uint32_t grf[8]; +typedef uint32_t mrf[8]; +typedef uint8_t cr[12]; +typedef uint32_t sr; + +#define DWORD8(x) {x, x, x, x, x, x, x, x} + +const static grf protocol_version = DWORD8(DEBUG_PROTOCOL_VERSION); +const static grf eu_msg = DWORD8(STATE_EU_MSG); +const static grf cpu_ack = DWORD8(STATE_CPU_ACK); + +struct eu_state { + mrf m_regs[15]; + grf g_regs[16]; + grf pad; + +/* 0x400 */ + cr cr0; + sr sr0; + uint32_t beef_pad[4]; + uint8_t pad2[992 + 1024]; + +/* 0xc00 COMMUNICATION_OFFSET */ + grf version; + grf state_magic; + grf eu_tx; + grf eu_rx; + + uint8_t pad3[896]; +} __attribute__((packed)); + +static inline void +print_reg(uint8_t reg[32]) { + uint32_t *dwords = (uint32_t *)reg; + printf("%08x %08x %08x %08x %08x %08x %08x %08x", + dwords[7], dwords[6], dwords[5], dwords[4], + dwords[3], dwords[2], dwords[1], dwords[0]); +} + +static inline void +print_creg(uint8_t reg[12]) { + uint32_t *dwords = (uint32_t *)reg; + printf("%08x %08x %08x", dwords[2], dwords[1], dwords[0]); +} +#endif + +#endif diff --git a/lib/drmtest.c b/lib/drmtest.c new file mode 100644 index 00000000..2101f6a9 --- /dev/null +++ b/lib/drmtest.c @@ -0,0 +1,779 @@ +/* + * Copyright © 2007, 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <string.h> +#include <sys/mman.h> +#include <signal.h> +#include <pciaccess.h> +#include <math.h> + +#include "drmtest.h" +#include "i915_drm.h" +#include "intel_chipset.h" +#include "intel_gpu_tools.h" + +/* This file contains a bunch of wrapper functions to directly use gem ioctls. + * Mostly useful to write kernel tests. */ + +static int +is_intel(int fd) +{ + struct drm_i915_getparam gp; + int devid; + + gp.param = I915_PARAM_CHIPSET_ID; + gp.value = &devid; + + if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp))) + return 0; + + return IS_INTEL(devid); +} + +bool gem_uses_aliasing_ppgtt(int fd) +{ + struct drm_i915_getparam gp; + int val; + + gp.param = 18; /* HAS_ALIASING_PPGTT */ + gp.value = &val; + + if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp))) + return 0; + + return val; +} + +int gem_available_fences(int fd) +{ + struct drm_i915_getparam gp; + int val; + + gp.param = I915_PARAM_NUM_FENCES_AVAIL; + gp.value = &val; + + if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp))) + return 0; + + return val; +} + + +/* Ensure the gpu is idle by launching a nop execbuf and stalling for it. */ +void gem_quiescent_gpu(int fd) +{ + uint32_t batch[2] = {MI_BATCH_BUFFER_END, 0}; + uint32_t handle; + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 gem_exec[1]; + + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, sizeof(batch)); + + gem_exec[0].handle = handle; + gem_exec[0].relocation_count = 0; + gem_exec[0].relocs_ptr = 0; + gem_exec[0].alignment = 0; + gem_exec[0].offset = 0; + gem_exec[0].flags = 0; + gem_exec[0].rsvd1 = 0; + gem_exec[0].rsvd2 = 0; + + execbuf.buffers_ptr = (uintptr_t)gem_exec; + execbuf.buffer_count = 1; + execbuf.batch_start_offset = 0; + execbuf.batch_len = 8; + execbuf.cliprects_ptr = 0; + execbuf.num_cliprects = 0; + execbuf.DR1 = 0; + execbuf.DR4 = 0; + execbuf.flags = 0; + i915_execbuffer2_set_context_id(execbuf, 0); + execbuf.rsvd2 = 0; + + do_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); + + gem_sync(fd, handle); +} + +static bool is_master(int fd) +{ + drm_client_t client; + int ret; + + /* Check that we're the only opener and authed. */ + client.idx = 0; + ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client); + assert (ret == 0); + if (!client.auth) { + return 0; + } + client.idx = 1; + ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client); + if (ret != -1 || errno != EINVAL) { + return 0; + } + return 1; +} + +/** + * drm_get_card() - get an intel card number for use in /dev or /sys + * + * @master: -1 not a master, 0 don't care, 1 is the master + * + * returns -1 on error + */ +int drm_get_card(int master) +{ + char *name; + int i, fd; + + for (i = 0; i < 16; i++) { + int ret; + + ret = asprintf(&name, "/dev/dri/card%u", i); + if (ret == -1) + return -1; + fd = open(name, O_RDWR); + free(name); + + if (fd == -1) + continue; + + if (is_intel(fd) && master == 0) { + gem_quiescent_gpu(fd); + close(fd); + break; + } + + if (master == 1 && is_master(fd)) { + close(fd); + break; + } + + if (master == -1 && !is_master(fd)) { + close(fd); + break; + } + + close(fd); + } + + return i; +} + +/** Open the first DRM device we can find, searching up to 16 device nodes */ +int drm_open_any(void) +{ + char *name; + int ret, fd; + + ret = asprintf(&name, "/dev/dri/card%d", drm_get_card(0)); + if (ret == -1) + return -1; + + fd = open(name, O_RDWR); + free(name); + + if (fd == -1) + fprintf(stderr, "failed to open any drm device. retry as root?\n"); + + assert(is_intel(fd)); + + return fd; +} + +/** + * Open the first DRM device we can find where we end up being the master. + */ +int drm_open_any_master(void) +{ + char *name; + int ret, fd; + + ret = asprintf(&name, "/dev/dri/card%d", drm_get_card(1)); + if (ret == -1) + return -1; + + fd = open(name, O_RDWR); + free(name); + if (fd == -1) + fprintf(stderr, "Couldn't find an un-controlled DRM device\n"); + + assert(is_intel(fd)); + + return fd; +} + +void gem_set_tiling(int fd, uint32_t handle, int tiling, int stride) +{ + struct drm_i915_gem_set_tiling st; + int ret; + + memset(&st, 0, sizeof(st)); + do { + st.handle = handle; + st.tiling_mode = tiling; + st.stride = tiling ? stride : 0; + + ret = ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &st); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + assert(ret == 0); + assert(st.tiling_mode == tiling); +} + +void gem_close(int fd, uint32_t handle) +{ + struct drm_gem_close close_bo; + + close_bo.handle = handle; + do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo); +} + +void gem_write(int fd, uint32_t handle, uint32_t offset, const void *buf, uint32_t size) +{ + struct drm_i915_gem_pwrite gem_pwrite; + + gem_pwrite.handle = handle; + gem_pwrite.offset = offset; + gem_pwrite.size = size; + gem_pwrite.data_ptr = (uintptr_t)buf; + do_ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite); +} + +void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t length) +{ + struct drm_i915_gem_pread gem_pread; + + gem_pread.handle = handle; + gem_pread.offset = offset; + gem_pread.size = length; + gem_pread.data_ptr = (uintptr_t)buf; + do_ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &gem_pread); +} + +void gem_set_domain(int fd, uint32_t handle, + uint32_t read_domains, uint32_t write_domain) +{ + struct drm_i915_gem_set_domain set_domain; + + set_domain.handle = handle; + set_domain.read_domains = read_domains; + set_domain.write_domain = write_domain; + + do_ioctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain); +} + +void gem_sync(int fd, uint32_t handle) +{ + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); +} + +uint32_t gem_create(int fd, int size) +{ + struct drm_i915_gem_create create; + + create.handle = 0; + create.size = size; + do_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); + assert(create.handle); + + return create.handle; +} + +void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot) +{ + struct drm_i915_gem_mmap_gtt mmap_arg; + void *ptr; + + mmap_arg.handle = handle; + if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg)) + return NULL; + + ptr = mmap64(0, size, prot, MAP_SHARED, fd, mmap_arg.offset); + if (ptr == MAP_FAILED) + ptr = NULL; + + return ptr; +} + +void *gem_mmap__cpu(int fd, uint32_t handle, int size, int prot) +{ + struct drm_i915_gem_mmap mmap_arg; + + mmap_arg.handle = handle; + mmap_arg.offset = 0; + mmap_arg.size = size; + if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg)) + return NULL; + + return (void *)(uintptr_t)mmap_arg.addr_ptr; +} + +uint64_t gem_aperture_size(int fd) +{ + struct drm_i915_gem_get_aperture aperture; + + aperture.aper_size = 256*1024*1024; + do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); + return aperture.aper_size; +} + +uint64_t gem_mappable_aperture_size(void) +{ + struct pci_device *pci_dev; + int bar; + pci_dev = intel_get_pci_device(); + + if (intel_gen(pci_dev->device_id) < 3) + bar = 0; + else + bar = 2; + + return pci_dev->regions[bar].size; +} + +int gem_madvise(int fd, uint32_t handle, int state) +{ + struct drm_i915_gem_madvise madv; + + madv.handle = handle; + madv.madv = state; + madv.retained = 1; + do_ioctl(fd, DRM_IOCTL_I915_GEM_MADVISE, &madv); + + return madv.retained; +} + +/* prime */ +int prime_handle_to_fd(int fd, uint32_t handle) +{ + struct drm_prime_handle args; + + args.handle = handle; + args.flags = DRM_CLOEXEC; + args.fd = -1; + + do_ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); + + return args.fd; +} + +uint32_t prime_fd_to_handle(int fd, int dma_buf_fd) +{ + struct drm_prime_handle args; + + args.fd = dma_buf_fd; + args.flags = 0; + args.handle = 0; + + do_ioctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); + + return args.handle; +} + +/* signal interrupt helpers */ +static pid_t signal_helper = -1; +long long int sig_stat; +static void signal_helper_process(pid_t pid) +{ + /* Interrupt the parent process at 500Hz, just to be annoying */ + while (1) { + usleep(1000 * 1000 / 500); + if (kill(pid, SIGUSR1)) /* Parent has died, so must we. */ + exit(0); + } +} + +static void sig_handler(int i) +{ + sig_stat++; +} + +void drmtest_fork_signal_helper(void) +{ + pid_t pid; + + signal(SIGUSR1, sig_handler); + pid = fork(); + if (pid == 0) { + signal_helper_process(getppid()); + return; + } + + signal_helper = pid; +} + +void drmtest_stop_signal_helper(void) +{ + if (signal_helper != -1) + kill(signal_helper, SIGQUIT); + + if (sig_stat) + fprintf(stderr, "signal handler called %llu times\n", sig_stat); + + signal_helper = -1; +} + +/* other helpers */ +void drmtest_exchange_int(void *array, unsigned i, unsigned j) +{ + int *int_arr, tmp; + int_arr = array; + + tmp = int_arr[i]; + int_arr[i] = int_arr[j]; + int_arr[j] = tmp; +} + +void drmtest_permute_array(void *array, unsigned size, + void (*exchange_func)(void *array, + unsigned i, + unsigned j)) +{ + int i; + + for (i = size - 1; i > 1; i--) { + /* yes, not perfectly uniform, who cares */ + long l = random() % (i +1); + if (i != l) + exchange_func(array, i, l); + } +} + +void drmtest_progress(const char *header, uint64_t i, uint64_t total) +{ + if (i+1 >= total) { + fprintf(stderr, "\r%s100%%\n", header); + return; + } + + /* only bother updating about every 0.5% */ + if (i % (total / 200) == 0 || i+1 >= total) { + fprintf(stderr, "\r%s%3llu%%", header, + (long long unsigned) i * 100 / total); + } +} + +/* mappable aperture trasher helper */ +drm_intel_bo **trash_bos; +int num_trash_bos; + +void drmtest_init_aperture_trashers(drm_intel_bufmgr *bufmgr) +{ + int i; + + num_trash_bos = gem_mappable_aperture_size() / (1024*1024); + + trash_bos = malloc(num_trash_bos * sizeof(drm_intel_bo *)); + assert(trash_bos); + + for (i = 0; i < num_trash_bos; i++) + trash_bos[i] = drm_intel_bo_alloc(bufmgr, "trash bo", 1024*1024, 4096); +} + +void drmtest_trash_aperture(void) +{ + int i; + uint8_t *gtt_ptr; + + for (i = 0; i < num_trash_bos; i++) { + drm_intel_gem_bo_map_gtt(trash_bos[i]); + gtt_ptr = trash_bos[i]->virtual; + *gtt_ptr = 0; + drm_intel_gem_bo_unmap_gtt(trash_bos[i]); + } +} + +void drmtest_cleanup_aperture_trashers(void) +{ + int i; + + for (i = 0; i < num_trash_bos; i++) + drm_intel_bo_unreference(trash_bos[i]); + + free(trash_bos); +} + +/* helpers to create nice-looking framebuffers */ +static cairo_surface_t * +paint_allocate_surface(int fd, int width, int height, int depth, int bpp, + bool tiled, + struct kmstest_fb *fb_info) +{ + cairo_format_t format; + struct drm_i915_gem_set_tiling set_tiling; + int size; + unsigned stride; + uint32_t *fb_ptr; + + if (tiled) { + int v; + + /* Round the tiling up to the next power-of-two and the + * region up to the next pot fence size so that this works + * on all generations. + * + * This can still fail if the framebuffer is too large to + * be tiled. But then that failure is expected. + */ + + v = width * bpp / 8; + for (stride = 512; stride < v; stride *= 2) + ; + + v = stride * height; + for (size = 1024*1024; size < v; size *= 2) + ; + } else { + /* Scan-out has a 64 byte alignment restriction */ + stride = (width * (bpp / 8) + 63) & ~63; + size = stride * height; + } + + switch (depth) { + case 16: + format = CAIRO_FORMAT_RGB16_565; + break; + case 24: + format = CAIRO_FORMAT_RGB24; + break; +#if 0 + case 30: + format = CAIRO_FORMAT_RGB30; + break; +#endif + case 32: + format = CAIRO_FORMAT_ARGB32; + break; + default: + fprintf(stderr, "bad depth %d\n", depth); + return NULL; + } + + assert (bpp >= depth); + + fb_info->gem_handle = gem_create(fd, size); + + if (tiled) { + set_tiling.handle = fb_info->gem_handle; + set_tiling.tiling_mode = I915_TILING_X; + set_tiling.stride = stride; + if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling)) { + fprintf(stderr, "set tiling failed: %s (stride=%d, size=%d)\n", + strerror(errno), stride, size); + return NULL; + } + } + + fb_ptr = gem_mmap(fd, fb_info->gem_handle, size, PROT_READ | PROT_WRITE); + + fb_info->stride = stride; + fb_info->size = size; + + return cairo_image_surface_create_for_data((unsigned char *)fb_ptr, + format, width, height, + stride); +} + +static void +paint_color_gradient(cairo_t *cr, int x, int y, int w, int h, + int r, int g, int b) +{ + cairo_pattern_t *pat; + + pat = cairo_pattern_create_linear(x, y, x + w, y + h); + cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1); + cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1); + + cairo_rectangle(cr, x, y, w, h); + cairo_set_source(cr, pat); + cairo_fill(cr); + cairo_pattern_destroy(pat); +} + +static void +paint_test_patterns(cairo_t *cr, int width, int height) +{ + double gr_height, gr_width; + int x, y; + + y = height * 0.10; + gr_width = width * 0.75; + gr_height = height * 0.08; + x = (width / 2) - (gr_width / 2); + + paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0); + + y += gr_height; + paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0); + + y += gr_height; + paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1); + + y += gr_height; + paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1); +} + +enum corner { + topleft, + topright, + bottomleft, + bottomright, +}; + +static void +paint_marker(cairo_t *cr, int x, int y, char *str, enum corner text_location) +{ + cairo_text_extents_t extents; + int xoff, yoff; + + cairo_set_font_size(cr, 18); + cairo_text_extents(cr, str, &extents); + + switch (text_location) { + case topleft: + xoff = -20; + xoff -= extents.width; + yoff = -20; + break; + case topright: + xoff = 20; + yoff = -20; + break; + case bottomleft: + xoff = -20; + xoff -= extents.width; + yoff = 20; + break; + case bottomright: + xoff = 20; + yoff = 20; + break; + default: + xoff = 0; + yoff = 0; + } + + cairo_move_to(cr, x, y - 20); + cairo_line_to(cr, x, y + 20); + cairo_move_to(cr, x - 20, y); + cairo_line_to(cr, x + 20, y); + cairo_new_sub_path(cr); + cairo_arc(cr, x, y, 10, 0, M_PI * 2); + cairo_set_line_width(cr, 4); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_set_line_width(cr, 2); + cairo_stroke(cr); + + cairo_move_to(cr, x + xoff, y + yoff); + cairo_text_path(cr, str); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_fill(cr); +} + +unsigned int kmstest_create_fb(int fd, int width, int height, int bpp, + int depth, bool tiled, + struct kmstest_fb *fb_info, + kmstest_paint_func paint_func, + void *func_arg) +{ + cairo_surface_t *surface; + cairo_status_t status; + cairo_t *cr; + char buf[128]; + int ret; + unsigned int fb_id; + + surface = paint_allocate_surface(fd, width, height, depth, bpp, + tiled, fb_info); + assert(surface); + + cr = cairo_create(surface); + + paint_test_patterns(cr, width, height); + + cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); + + /* Paint corner markers */ + snprintf(buf, sizeof buf, "(%d, %d)", 0, 0); + paint_marker(cr, 0, 0, buf, bottomright); + snprintf(buf, sizeof buf, "(%d, %d)", width, 0); + paint_marker(cr, width, 0, buf, bottomleft); + snprintf(buf, sizeof buf, "(%d, %d)", 0, height); + paint_marker(cr, 0, height, buf, topright); + snprintf(buf, sizeof buf, "(%d, %d)", width, height); + paint_marker(cr, width, height, buf, topleft); + + if (paint_func) + paint_func(cr, width, height, func_arg); + + status = cairo_status(cr); + assert(!status); + cairo_destroy(cr); + + ret = drmModeAddFB(fd, width, height, depth, bpp, + fb_info->stride, + fb_info->gem_handle, &fb_id); + + assert(ret == 0); + cairo_surface_destroy(surface); + + fb_info->fb_id = fb_id; + + return fb_id; +} + +void kmstest_dump_mode(drmModeModeInfo *mode) +{ + printf(" %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d\n", + mode->name, + mode->vrefresh, + mode->hdisplay, + mode->hsync_start, + mode->hsync_end, + mode->htotal, + mode->vdisplay, + mode->vsync_start, + mode->vsync_end, + mode->vtotal, + mode->flags, + mode->type, + mode->clock); + fflush(stdout); +} + diff --git a/lib/drmtest.h b/lib/drmtest.h new file mode 100644 index 00000000..0cffa394 --- /dev/null +++ b/lib/drmtest.h @@ -0,0 +1,114 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <cairo.h> + +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "intel_batchbuffer.h" + +int drm_get_card(int master); +int drm_open_any(void); +int drm_open_any_master(void); + +void gem_quiescent_gpu(int fd); + +/* ioctl wrappers and similar stuff for bare metal testing */ +void gem_set_tiling(int fd, uint32_t handle, int tiling, int stride); +void gem_close(int fd, uint32_t handle); +void gem_write(int fd, uint32_t handle, uint32_t offset, const void *buf, uint32_t size); +void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t size); +void gem_set_domain(int fd, uint32_t handle, + uint32_t read_domains, uint32_t write_domain); +void gem_sync(int fd, uint32_t handle); +uint32_t gem_create(int fd, int size); + +void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot); +void *gem_mmap__cpu(int fd, uint32_t handle, int size, int prot); +#define gem_mmap gem_mmap__gtt + +uint64_t gem_aperture_size(int fd); +uint64_t gem_mappable_aperture_size(void); +int gem_madvise(int fd, uint32_t handle, int state); + +/* feature test helpers */ +bool gem_uses_aliasing_ppgtt(int fd); +int gem_available_fences(int fd); + +/* prime */ +int prime_handle_to_fd(int fd, uint32_t handle); +uint32_t prime_fd_to_handle(int fd, int dma_buf_fd); + +/* generally useful helpers */ +void drmtest_fork_signal_helper(void); +void drmtest_stop_signal_helper(void); +void drmtest_exchange_int(void *array, unsigned i, unsigned j); +void drmtest_permute_array(void *array, unsigned size, + void (*exchange_func)(void *array, + unsigned i, + unsigned j)); +void drmtest_progress(const char *header, uint64_t i, uint64_t total); + +/* helpers based upon the libdrm buffer manager */ +void drmtest_init_aperture_trashers(drm_intel_bufmgr *bufmgr); +void drmtest_trash_aperture(void); +void drmtest_cleanup_aperture_trashers(void); + +/* helpers to create nice-looking framebuffers */ +struct kmstest_fb { + uint32_t fb_id; + uint32_t gem_handle; + unsigned stride; + unsigned size; +}; + +typedef void (*kmstest_paint_func)(cairo_t *cr, int width, int height, void *priv); + +unsigned int kmstest_create_fb(int fd, int width, int height, int bpp, + int depth, bool tiled, + struct kmstest_fb *fb_info, + kmstest_paint_func paint_func, + void *func_arg); +void kmstest_dump_mode(drmModeModeInfo *mode); + +inline static void _do_or_die(const char *function, int line, int ret) +{ + if (ret == 0) + return; + + fprintf(stderr, "%s:%d failed, ret=%d, errno=%d\n", + function, line, ret, errno); + abort(); +} +#define do_or_die(x) _do_or_die(__FUNCTION__, __LINE__, x) +#define do_ioctl(fd, ptr, sz) do_or_die(drmIoctl((fd), (ptr), (sz))) diff --git a/lib/gen6_render.h b/lib/gen6_render.h new file mode 100644 index 00000000..2c63c9e7 --- /dev/null +++ b/lib/gen6_render.h @@ -0,0 +1,1553 @@ +#ifndef GEN6_RENDER_H +#define GEN6_RENDER_H + +#define GEN6_3D(Pipeline,Opcode,Subopcode) ((3 << 29) | \ + ((Pipeline) << 27) | \ + ((Opcode) << 24) | \ + ((Subopcode) << 16)) + +#define GEN6_STATE_BASE_ADDRESS GEN6_3D(0, 1, 1) +#define GEN6_STATE_SIP GEN6_3D(0, 1, 2) + +#define GEN6_PIPELINE_SELECT GEN6_3D(1, 1, 4) + +#define GEN6_MEDIA_STATE_POINTERS GEN6_3D(2, 0, 0) +#define GEN6_MEDIA_OBJECT GEN6_3D(2, 1, 0) + +#define GEN6_3DSTATE_BINDING_TABLE_POINTERS GEN6_3D(3, 0, 1) +# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_PS (1 << 12)/* for GEN6 */ +# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_GS (1 << 9) /* for GEN6 */ +# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_VS (1 << 8) /* for GEN6 */ + +#define GEN6_3DSTATE_VERTEX_BUFFERS GEN6_3D(3, 0, 8) +#define GEN6_3DSTATE_VERTEX_ELEMENTS GEN6_3D(3, 0, 9) +#define GEN6_3DSTATE_INDEX_BUFFER GEN6_3D(3, 0, 0xa) +#define GEN6_3DSTATE_VF_STATISTICS GEN6_3D(3, 0, 0xb) + +#define GEN6_3DSTATE_DRAWING_RECTANGLE GEN6_3D(3, 1, 0) +#define GEN6_3DSTATE_CONSTANT_COLOR GEN6_3D(3, 1, 1) +#define GEN6_3DSTATE_SAMPLER_PALETTE_LOAD GEN6_3D(3, 1, 2) +#define GEN6_3DSTATE_CHROMA_KEY GEN6_3D(3, 1, 4) +#define GEN6_3DSTATE_DEPTH_BUFFER GEN6_3D(3, 1, 5) +# define GEN6_3DSTATE_DEPTH_BUFFER_TYPE_SHIFT 29 +# define GEN6_3DSTATE_DEPTH_BUFFER_FORMAT_SHIFT 18 + +#define GEN6_3DSTATE_POLY_STIPPLE_OFFSET GEN6_3D(3, 1, 6) +#define GEN6_3DSTATE_POLY_STIPPLE_PATTERN GEN6_3D(3, 1, 7) +#define GEN6_3DSTATE_LINE_STIPPLE GEN6_3D(3, 1, 8) +#define GEN6_3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP GEN6_3D(3, 1, 9) +/* These two are BLC and CTG only, not BW or CL */ +#define GEN6_3DSTATE_AA_LINE_PARAMS GEN6_3D(3, 1, 0xa) +#define GEN6_3DSTATE_GS_SVB_INDEX GEN6_3D(3, 1, 0xb) + +#define GEN6_3DPRIMITIVE GEN6_3D(3, 3, 0) + +#define GEN6_3DSTATE_CLEAR_PARAMS GEN6_3D(3, 1, 0x10) +/* DW1 */ +# define GEN6_3DSTATE_DEPTH_CLEAR_VALID (1 << 15) + +#define GEN6_3DSTATE_SAMPLER_STATE_POINTERS GEN6_3D(3, 0, 0x02) +# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_PS (1 << 12) +# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_GS (1 << 9) +# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_VS (1 << 8) + +#define GEN6_3DSTATE_URB GEN6_3D(3, 0, 0x05) +/* DW1 */ +# define GEN6_3DSTATE_URB_VS_SIZE_SHIFT 16 +# define GEN6_3DSTATE_URB_VS_ENTRIES_SHIFT 0 +/* DW2 */ +# define GEN6_3DSTATE_URB_GS_ENTRIES_SHIFT 8 +# define GEN6_3DSTATE_URB_GS_SIZE_SHIFT 0 + +#define GEN6_3DSTATE_VIEWPORT_STATE_POINTERS GEN6_3D(3, 0, 0x0d) +# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CC (1 << 12) +# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_SF (1 << 11) +# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CLIP (1 << 10) + +#define GEN6_3DSTATE_CC_STATE_POINTERS GEN6_3D(3, 0, 0x0e) + +#define GEN6_3DSTATE_VS GEN6_3D(3, 0, 0x10) + +#define GEN6_3DSTATE_GS GEN6_3D(3, 0, 0x11) +/* DW4 */ +# define GEN6_3DSTATE_GS_DISPATCH_START_GRF_SHIFT 0 + +#define GEN6_3DSTATE_CLIP GEN6_3D(3, 0, 0x12) + +#define GEN6_3DSTATE_SF GEN6_3D(3, 0, 0x13) +/* DW1 */ +# define GEN6_3DSTATE_SF_NUM_OUTPUTS_SHIFT 22 +# define GEN6_3DSTATE_SF_URB_ENTRY_READ_LENGTH_SHIFT 11 +# define GEN6_3DSTATE_SF_URB_ENTRY_READ_OFFSET_SHIFT 4 +/* DW2 */ +/* DW3 */ +# define GEN6_3DSTATE_SF_CULL_BOTH (0 << 29) +# define GEN6_3DSTATE_SF_CULL_NONE (1 << 29) +# define GEN6_3DSTATE_SF_CULL_FRONT (2 << 29) +# define GEN6_3DSTATE_SF_CULL_BACK (3 << 29) +/* DW4 */ +# define GEN6_3DSTATE_SF_TRI_PROVOKE_SHIFT 29 +# define GEN6_3DSTATE_SF_LINE_PROVOKE_SHIFT 27 +# define GEN6_3DSTATE_SF_TRIFAN_PROVOKE_SHIFT 25 + +#define GEN6_3DSTATE_WM GEN6_3D(3, 0, 0x14) +/* DW2 */ +# define GEN6_3DSTATE_WM_SAMPLER_COUNT_SHIFT 27 +# define GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT 18 +/* DW4 */ +# define GEN6_3DSTATE_WM_DISPATCH_START_GRF_0_SHIFT 16 +/* DW5 */ +# define GEN6_3DSTATE_WM_MAX_THREADS_SHIFT 25 +# define GEN6_3DSTATE_WM_DISPATCH_ENABLE (1 << 19) +# define GEN6_3DSTATE_WM_16_DISPATCH_ENABLE (1 << 1) +# define GEN6_3DSTATE_WM_8_DISPATCH_ENABLE (1 << 0) +/* DW6 */ +# define GEN6_3DSTATE_WM_NUM_SF_OUTPUTS_SHIFT 20 +# define GEN6_3DSTATE_WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 15) +# define GEN6_3DSTATE_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC (1 << 14) +# define GEN6_3DSTATE_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC (1 << 13) +# define GEN6_3DSTATE_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 12) +# define GEN6_3DSTATE_WM_PERSPECTIVE_CENTROID_BARYCENTRIC (1 << 11) +# define GEN6_3DSTATE_WM_PERSPECTIVE_PIXEL_BARYCENTRIC (1 << 10) + + +#define GEN6_3DSTATE_CONSTANT_VS GEN6_3D(3, 0, 0x15) +#define GEN6_3DSTATE_CONSTANT_GS GEN6_3D(3, 0, 0x16) +#define GEN6_3DSTATE_CONSTANT_PS GEN6_3D(3, 0, 0x17) + +#define GEN6_3DSTATE_SAMPLE_MASK GEN6_3D(3, 0, 0x18) + +#define GEN6_3DSTATE_MULTISAMPLE GEN6_3D(3, 1, 0x0d) +/* DW1 */ +# define GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_CENTER (0 << 4) +# define GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_UPPER_LEFT (1 << 4) +# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_1 (0 << 1) +# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_4 (2 << 1) +# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_8 (3 << 1) + +#define PIPELINE_SELECT_3D 0 +#define PIPELINE_SELECT_MEDIA 1 + +/* for GEN6_STATE_BASE_ADDRESS */ +#define BASE_ADDRESS_MODIFY (1 << 0) + +/* for GEN6_PIPE_CONTROL */ +#define GEN6_PIPE_CONTROL_NOWRITE (0 << 14) +#define GEN6_PIPE_CONTROL_WRITE_QWORD (1 << 14) +#define GEN6_PIPE_CONTROL_WRITE_DEPTH (2 << 14) +#define GEN6_PIPE_CONTROL_WRITE_TIME (3 << 14) +#define GEN6_PIPE_CONTROL_DEPTH_STALL (1 << 13) +#define GEN6_PIPE_CONTROL_WC_FLUSH (1 << 12) +#define GEN6_PIPE_CONTROL_IS_FLUSH (1 << 11) +#define GEN6_PIPE_CONTROL_TC_FLUSH (1 << 10) +#define GEN6_PIPE_CONTROL_NOTIFY_ENABLE (1 << 8) +#define GEN6_PIPE_CONTROL_GLOBAL_GTT (1 << 2) +#define GEN6_PIPE_CONTROL_LOCAL_PGTT (0 << 2) +#define GEN6_PIPE_CONTROL_DEPTH_CACHE_FLUSH (1 << 0) + +/* VERTEX_BUFFER_STATE Structure */ +#define VB0_BUFFER_INDEX_SHIFT 26 +#define VB0_VERTEXDATA (0 << 20) +#define VB0_INSTANCEDATA (1 << 20) +#define VB0_BUFFER_PITCH_SHIFT 0 + +/* VERTEX_ELEMENT_STATE Structure */ +#define VE0_VERTEX_BUFFER_INDEX_SHIFT 26 /* for GEN6 */ +#define VE0_VALID (1 << 25) /* for GEN6 */ +#define VE0_FORMAT_SHIFT 16 +#define VE0_OFFSET_SHIFT 0 +#define VE1_VFCOMPONENT_0_SHIFT 28 +#define VE1_VFCOMPONENT_1_SHIFT 24 +#define VE1_VFCOMPONENT_2_SHIFT 20 +#define VE1_VFCOMPONENT_3_SHIFT 16 +#define VE1_DESTINATION_ELEMENT_OFFSET_SHIFT 0 + +/* 3DPRIMITIVE bits */ +#define GEN6_3DPRIMITIVE_VERTEX_SEQUENTIAL (0 << 15) +#define GEN6_3DPRIMITIVE_VERTEX_RANDOM (1 << 15) +/* Primitive types are in gen6_defines.h */ +#define GEN6_3DPRIMITIVE_TOPOLOGY_SHIFT 10 + +#define GEN6_SVG_CTL 0x7400 + +#define GEN6_SVG_CTL_GS_BA (0 << 8) +#define GEN6_SVG_CTL_SS_BA (1 << 8) +#define GEN6_SVG_CTL_IO_BA (2 << 8) +#define GEN6_SVG_CTL_GS_AUB (3 << 8) +#define GEN6_SVG_CTL_IO_AUB (4 << 8) +#define GEN6_SVG_CTL_SIP (5 << 8) + +#define GEN6_SVG_RDATA 0x7404 +#define GEN6_SVG_WORK_CTL 0x7408 + +#define GEN6_VF_CTL 0x7500 + +#define GEN6_VF_CTL_SNAPSHOT_COMPLETE (1 << 31) +#define GEN6_VF_CTL_SNAPSHOT_MUX_SELECT_THREADID (0 << 8) +#define GEN6_VF_CTL_SNAPSHOT_MUX_SELECT_VF_DEBUG (1 << 8) +#define GEN6_VF_CTL_SNAPSHOT_TYPE_VERTEX_SEQUENCE (0 << 4) +#define GEN6_VF_CTL_SNAPSHOT_TYPE_VERTEX_INDEX (1 << 4) +#define GEN6_VF_CTL_SKIP_INITIAL_PRIMITIVES (1 << 3) +#define GEN6_VF_CTL_MAX_PRIMITIVES_LIMIT_ENABLE (1 << 2) +#define GEN6_VF_CTL_VERTEX_RANGE_LIMIT_ENABLE (1 << 1) +#define GEN6_VF_CTL_SNAPSHOT_ENABLE (1 << 0) + +#define GEN6_VF_STRG_VAL 0x7504 +#define GEN6_VF_STR_VL_OVR 0x7508 +#define GEN6_VF_VC_OVR 0x750c +#define GEN6_VF_STR_PSKIP 0x7510 +#define GEN6_VF_MAX_PRIM 0x7514 +#define GEN6_VF_RDATA 0x7518 + +#define GEN6_VS_CTL 0x7600 +#define GEN6_VS_CTL_SNAPSHOT_COMPLETE (1 << 31) +#define GEN6_VS_CTL_SNAPSHOT_MUX_VERTEX_0 (0 << 8) +#define GEN6_VS_CTL_SNAPSHOT_MUX_VERTEX_1 (1 << 8) +#define GEN6_VS_CTL_SNAPSHOT_MUX_VALID_COUNT (2 << 8) +#define GEN6_VS_CTL_SNAPSHOT_MUX_VS_KERNEL_POINTER (3 << 8) +#define GEN6_VS_CTL_SNAPSHOT_ALL_THREADS (1 << 2) +#define GEN6_VS_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) +#define GEN6_VS_CTL_SNAPSHOT_ENABLE (1 << 0) + +#define GEN6_VS_STRG_VAL 0x7604 +#define GEN6_VS_RDATA 0x7608 + +#define GEN6_SF_CTL 0x7b00 +#define GEN6_SF_CTL_SNAPSHOT_COMPLETE (1 << 31) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_0_FF_ID (0 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_0_REL_COUNT (1 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_1_FF_ID (2 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_1_REL_COUNT (3 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_2_FF_ID (4 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_2_REL_COUNT (5 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_COUNT (6 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_SF_KERNEL_POINTER (7 << 8) +#define GEN6_SF_CTL_MIN_MAX_PRIMITIVE_RANGE_ENABLE (1 << 4) +#define GEN6_SF_CTL_DEBUG_CLIP_RECTANGLE_ENABLE (1 << 3) +#define GEN6_SF_CTL_SNAPSHOT_ALL_THREADS (1 << 2) +#define GEN6_SF_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) +#define GEN6_SF_CTL_SNAPSHOT_ENABLE (1 << 0) + +#define GEN6_SF_STRG_VAL 0x7b04 +#define GEN6_SF_RDATA 0x7b18 + +#define GEN6_WIZ_CTL 0x7c00 +#define GEN6_WIZ_CTL_SNAPSHOT_COMPLETE (1 << 31) +#define GEN6_WIZ_CTL_SUBSPAN_INSTANCE_SHIFT 16 +#define GEN6_WIZ_CTL_SNAPSHOT_MUX_WIZ_KERNEL_POINTER (0 << 8) +#define GEN6_WIZ_CTL_SNAPSHOT_MUX_SUBSPAN_INSTANCE (1 << 8) +#define GEN6_WIZ_CTL_SNAPSHOT_MUX_PRIMITIVE_SEQUENCE (2 << 8) +#define GEN6_WIZ_CTL_SINGLE_SUBSPAN_DISPATCH (1 << 6) +#define GEN6_WIZ_CTL_IGNORE_COLOR_SCOREBOARD_STALLS (1 << 5) +#define GEN6_WIZ_CTL_ENABLE_SUBSPAN_INSTANCE_COMPARE (1 << 4) +#define GEN6_WIZ_CTL_USE_UPSTREAM_SNAPSHOT_FLAG (1 << 3) +#define GEN6_WIZ_CTL_SNAPSHOT_ALL_THREADS (1 << 2) +#define GEN6_WIZ_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) +#define GEN6_WIZ_CTL_SNAPSHOT_ENABLE (1 << 0) + +#define GEN6_WIZ_STRG_VAL 0x7c04 +#define GEN6_WIZ_RDATA 0x7c18 + +#define GEN6_TS_CTL 0x7e00 +#define GEN6_TS_CTL_SNAPSHOT_COMPLETE (1 << 31) +#define GEN6_TS_CTL_SNAPSHOT_MESSAGE_ERROR (0 << 8) +#define GEN6_TS_CTL_SNAPSHOT_INTERFACE_DESCRIPTOR (3 << 8) +#define GEN6_TS_CTL_SNAPSHOT_ALL_CHILD_THREADS (1 << 2) +#define GEN6_TS_CTL_SNAPSHOT_ALL_ROOT_THREADS (1 << 1) +#define GEN6_TS_CTL_SNAPSHOT_ENABLE (1 << 0) + +#define GEN6_TS_STRG_VAL 0x7e04 +#define GEN6_TS_RDATA 0x7e08 + +/* TD_CTL on gen6 is 0x7000, to not break stuff which depends on this... */ +#ifndef GEN6_TD_CTL +#define GEN6_TD_CTL 0x8000 +#endif +#define GEN6_TD_CTL_MUX_SHIFT 8 +#define GEN6_TD_CTL_EXTERNAL_HALT_R0_DEBUG_MATCH (1 << 7) +#define GEN6_TD_CTL_FORCE_EXTERNAL_HALT (1 << 6) +#define GEN6_TD_CTL_EXCEPTION_MASK_OVERRIDE (1 << 5) +#define GEN6_TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE (1 << 4) +#define GEN6_TD_CTL_BREAKPOINT_ENABLE (1 << 2) +#define GEN6_TD_CTL2 0x8004 +#define GEN6_TD_CTL2_ILLEGAL_OPCODE_EXCEPTION_OVERRIDE (1 << 28) +#define GEN6_TD_CTL2_MASKSTACK_EXCEPTION_OVERRIDE (1 << 26) +#define GEN6_TD_CTL2_SOFTWARE_EXCEPTION_OVERRIDE (1 << 25) +#define GEN6_TD_CTL2_ACTIVE_THREAD_LIMIT_SHIFT 16 +#define GEN6_TD_CTL2_ACTIVE_THREAD_LIMIT_ENABLE (1 << 8) +#define GEN6_TD_CTL2_THREAD_SPAWNER_EXECUTION_MASK_ENABLE (1 << 7) +#define GEN6_TD_CTL2_WIZ_EXECUTION_MASK_ENABLE (1 << 6) +#define GEN6_TD_CTL2_SF_EXECUTION_MASK_ENABLE (1 << 5) +#define GEN6_TD_CTL2_CLIPPER_EXECUTION_MASK_ENABLE (1 << 4) +#define GEN6_TD_CTL2_GS_EXECUTION_MASK_ENABLE (1 << 3) +#define GEN6_TD_CTL2_VS_EXECUTION_MASK_ENABLE (1 << 0) +#define GEN6_TD_VF_VS_EMSK 0x8008 +#define GEN6_TD_GS_EMSK 0x800c +#define GEN6_TD_CLIP_EMSK 0x8010 +#define GEN6_TD_SF_EMSK 0x8014 +#define GEN6_TD_WIZ_EMSK 0x8018 +#define GEN6_TD_0_6_EHTRG_VAL 0x801c +#define GEN6_TD_0_7_EHTRG_VAL 0x8020 +#define GEN6_TD_0_6_EHTRG_MSK 0x8024 +#define GEN6_TD_0_7_EHTRG_MSK 0x8028 +#define GEN6_TD_RDATA 0x802c +#define GEN6_TD_TS_EMSK 0x8030 + +#define GEN6_EU_CTL 0x8800 +#define GEN6_EU_CTL_SELECT_SHIFT 16 +#define GEN6_EU_CTL_DATA_MUX_SHIFT 8 +#define GEN6_EU_ATT_0 0x8810 +#define GEN6_EU_ATT_1 0x8814 +#define GEN6_EU_ATT_DATA_0 0x8820 +#define GEN6_EU_ATT_DATA_1 0x8824 +#define GEN6_EU_ATT_CLR_0 0x8830 +#define GEN6_EU_ATT_CLR_1 0x8834 +#define GEN6_EU_RDATA 0x8840 + +#define GEN6_3D(Pipeline,Opcode,Subopcode) ((3 << 29) | \ + ((Pipeline) << 27) | \ + ((Opcode) << 24) | \ + ((Subopcode) << 16)) + +#define GEN6_STATE_BASE_ADDRESS GEN6_3D(0, 1, 1) +#define GEN6_STATE_SIP GEN6_3D(0, 1, 2) + +#define GEN6_PIPELINE_SELECT GEN6_3D(1, 1, 4) + +#define GEN6_MEDIA_STATE_POINTERS GEN6_3D(2, 0, 0) +#define GEN6_MEDIA_OBJECT GEN6_3D(2, 1, 0) + +#define GEN6_3DSTATE_BINDING_TABLE_POINTERS GEN6_3D(3, 0, 1) +# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_PS (1 << 12)/* for GEN6 */ +# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_GS (1 << 9) /* for GEN6 */ +# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_VS (1 << 8) /* for GEN6 */ + +#define GEN6_3DSTATE_VERTEX_BUFFERS GEN6_3D(3, 0, 8) +#define GEN6_3DSTATE_VERTEX_ELEMENTS GEN6_3D(3, 0, 9) +#define GEN6_3DSTATE_INDEX_BUFFER GEN6_3D(3, 0, 0xa) +#define GEN6_3DSTATE_VF_STATISTICS GEN6_3D(3, 0, 0xb) + +#define GEN6_3DSTATE_DRAWING_RECTANGLE GEN6_3D(3, 1, 0) +#define GEN6_3DSTATE_CONSTANT_COLOR GEN6_3D(3, 1, 1) +#define GEN6_3DSTATE_SAMPLER_PALETTE_LOAD GEN6_3D(3, 1, 2) +#define GEN6_3DSTATE_CHROMA_KEY GEN6_3D(3, 1, 4) +#define GEN6_3DSTATE_DEPTH_BUFFER GEN6_3D(3, 1, 5) +# define GEN6_3DSTATE_DEPTH_BUFFER_TYPE_SHIFT 29 +# define GEN6_3DSTATE_DEPTH_BUFFER_FORMAT_SHIFT 18 + +#define GEN6_3DSTATE_POLY_STIPPLE_OFFSET GEN6_3D(3, 1, 6) +#define GEN6_3DSTATE_POLY_STIPPLE_PATTERN GEN6_3D(3, 1, 7) +#define GEN6_3DSTATE_LINE_STIPPLE GEN6_3D(3, 1, 8) +#define GEN6_3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP GEN6_3D(3, 1, 9) +/* These two are BLC and CTG only, not BW or CL */ +#define GEN6_3DSTATE_AA_LINE_PARAMS GEN6_3D(3, 1, 0xa) +#define GEN6_3DSTATE_GS_SVB_INDEX GEN6_3D(3, 1, 0xb) + +#define GEN6_PIPE_CONTROL GEN6_3D(3, 2, 0) + +#define GEN6_3DPRIMITIVE GEN6_3D(3, 3, 0) + +#define GEN6_3DSTATE_CLEAR_PARAMS GEN6_3D(3, 1, 0x10) +/* DW1 */ +# define GEN6_3DSTATE_DEPTH_CLEAR_VALID (1 << 15) + +/* for GEN6+ */ +#define GEN6_3DSTATE_SAMPLER_STATE_POINTERS GEN6_3D(3, 0, 0x02) +# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_PS (1 << 12) +# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_GS (1 << 9) +# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_VS (1 << 8) + +#define GEN6_3DSTATE_URB GEN6_3D(3, 0, 0x05) +/* DW1 */ +# define GEN6_3DSTATE_URB_VS_SIZE_SHIFT 16 +# define GEN6_3DSTATE_URB_VS_ENTRIES_SHIFT 0 +/* DW2 */ +# define GEN6_3DSTATE_URB_GS_ENTRIES_SHIFT 8 +# define GEN6_3DSTATE_URB_GS_SIZE_SHIFT 0 + +#define GEN6_3DSTATE_VIEWPORT_STATE_POINTERS GEN6_3D(3, 0, 0x0d) +# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CC (1 << 12) +# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_SF (1 << 11) +# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CLIP (1 << 10) + +#define GEN6_3DSTATE_CC_STATE_POINTERS GEN6_3D(3, 0, 0x0e) + +#define GEN6_3DSTATE_VS GEN6_3D(3, 0, 0x10) + +#define GEN6_3DSTATE_GS GEN6_3D(3, 0, 0x11) +/* DW4 */ +# define GEN6_3DSTATE_GS_DISPATCH_START_GRF_SHIFT 0 + +#define GEN6_3DSTATE_CLIP GEN6_3D(3, 0, 0x12) + +#define GEN6_3DSTATE_SF GEN6_3D(3, 0, 0x13) +/* DW1 */ +# define GEN6_3DSTATE_SF_NUM_OUTPUTS_SHIFT 22 +# define GEN6_3DSTATE_SF_URB_ENTRY_READ_LENGTH_SHIFT 11 +# define GEN6_3DSTATE_SF_URB_ENTRY_READ_OFFSET_SHIFT 4 +/* DW2 */ +/* DW3 */ +# define GEN6_3DSTATE_SF_CULL_BOTH (0 << 29) +# define GEN6_3DSTATE_SF_CULL_NONE (1 << 29) +# define GEN6_3DSTATE_SF_CULL_FRONT (2 << 29) +# define GEN6_3DSTATE_SF_CULL_BACK (3 << 29) +/* DW4 */ +# define GEN6_3DSTATE_SF_TRI_PROVOKE_SHIFT 29 +# define GEN6_3DSTATE_SF_LINE_PROVOKE_SHIFT 27 +# define GEN6_3DSTATE_SF_TRIFAN_PROVOKE_SHIFT 25 + + +#define GEN6_3DSTATE_WM GEN6_3D(3, 0, 0x14) +/* DW2 */ +# define GEN6_3DSTATE_WM_SAMPLER_COUNT_SHITF 27 +# define GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT 18 +/* DW4 */ +# define GEN6_3DSTATE_WM_DISPATCH_START_GRF_0_SHIFT 16 +/* DW5 */ +# define GEN6_3DSTATE_WM_MAX_THREADS_SHIFT 25 +# define GEN6_3DSTATE_WM_DISPATCH_ENABLE (1 << 19) +# define GEN6_3DSTATE_WM_16_DISPATCH_ENABLE (1 << 1) +# define GEN6_3DSTATE_WM_8_DISPATCH_ENABLE (1 << 0) +/* DW6 */ +# define GEN6_3DSTATE_WM_NUM_SF_OUTPUTS_SHIFT 20 +# define GEN6_3DSTATE_WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 15) +# define GEN6_3DSTATE_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC (1 << 14) +# define GEN6_3DSTATE_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC (1 << 13) +# define GEN6_3DSTATE_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 12) +# define GEN6_3DSTATE_WM_PERSPECTIVE_CENTROID_BARYCENTRIC (1 << 11) +# define GEN6_3DSTATE_WM_PERSPECTIVE_PIXEL_BARYCENTRIC (1 << 10) + + +#define GEN6_3DSTATE_CONSTANT_VS GEN6_3D(3, 0, 0x15) +#define GEN6_3DSTATE_CONSTANT_GS GEN6_3D(3, 0, 0x16) +#define GEN6_3DSTATE_CONSTANT_PS GEN6_3D(3, 0, 0x17) + +#define GEN6_3DSTATE_SAMPLE_MASK GEN6_3D(3, 0, 0x18) + +#define GEN6_3DSTATE_MULTISAMPLE GEN6_3D(3, 1, 0x0d) +/* DW1 */ +# define GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_CENTER (0 << 4) +# define GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_UPPER_LEFT (1 << 4) +# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_1 (0 << 1) +# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_4 (2 << 1) +# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_8 (3 << 1) + +#define PIPELINE_SELECT_3D 0 +#define PIPELINE_SELECT_MEDIA 1 + +#define UF0_CS_REALLOC (1 << 13) +#define UF0_VFE_REALLOC (1 << 12) +#define UF0_SF_REALLOC (1 << 11) +#define UF0_CLIP_REALLOC (1 << 10) +#define UF0_GS_REALLOC (1 << 9) +#define UF0_VS_REALLOC (1 << 8) +#define UF1_CLIP_FENCE_SHIFT 20 +#define UF1_GS_FENCE_SHIFT 10 +#define UF1_VS_FENCE_SHIFT 0 +#define UF2_CS_FENCE_SHIFT 20 +#define UF2_VFE_FENCE_SHIFT 10 +#define UF2_SF_FENCE_SHIFT 0 + +/* for GEN6_STATE_BASE_ADDRESS */ +#define BASE_ADDRESS_MODIFY (1 << 0) + +/* for GEN6_3DSTATE_PIPELINED_POINTERS */ +#define GEN6_GS_DISABLE 0 +#define GEN6_GS_ENABLE 1 +#define GEN6_CLIP_DISABLE 0 +#define GEN6_CLIP_ENABLE 1 + +/* for GEN6_PIPE_CONTROL */ +#define GEN6_PIPE_CONTROL_NOWRITE (0 << 14) +#define GEN6_PIPE_CONTROL_WRITE_QWORD (1 << 14) +#define GEN6_PIPE_CONTROL_WRITE_DEPTH (2 << 14) +#define GEN6_PIPE_CONTROL_WRITE_TIME (3 << 14) +#define GEN6_PIPE_CONTROL_DEPTH_STALL (1 << 13) +#define GEN6_PIPE_CONTROL_WC_FLUSH (1 << 12) +#define GEN6_PIPE_CONTROL_IS_FLUSH (1 << 11) +#define GEN6_PIPE_CONTROL_TC_FLUSH (1 << 10) +#define GEN6_PIPE_CONTROL_NOTIFY_ENABLE (1 << 8) +#define GEN6_PIPE_CONTROL_GLOBAL_GTT (1 << 2) +#define GEN6_PIPE_CONTROL_LOCAL_PGTT (0 << 2) +#define GEN6_PIPE_CONTROL_DEPTH_CACHE_FLUSH (1 << 0) + +/* 3DPRIMITIVE bits */ +#define GEN6_3DPRIMITIVE_VERTEX_SEQUENTIAL (0 << 15) +#define GEN6_3DPRIMITIVE_VERTEX_RANDOM (1 << 15) +/* Primitive types are in gen6_defines.h */ +#define GEN6_3DPRIMITIVE_TOPOLOGY_SHIFT 10 + +#define GEN6_SVG_CTL 0x7400 + +#define GEN6_SVG_CTL_GS_BA (0 << 8) +#define GEN6_SVG_CTL_SS_BA (1 << 8) +#define GEN6_SVG_CTL_IO_BA (2 << 8) +#define GEN6_SVG_CTL_GS_AUB (3 << 8) +#define GEN6_SVG_CTL_IO_AUB (4 << 8) +#define GEN6_SVG_CTL_SIP (5 << 8) + +#define GEN6_SVG_RDATA 0x7404 +#define GEN6_SVG_WORK_CTL 0x7408 + +#define GEN6_VF_CTL 0x7500 + +#define GEN6_VF_CTL_SNAPSHOT_COMPLETE (1 << 31) +#define GEN6_VF_CTL_SNAPSHOT_MUX_SELECT_THREADID (0 << 8) +#define GEN6_VF_CTL_SNAPSHOT_MUX_SELECT_VF_DEBUG (1 << 8) +#define GEN6_VF_CTL_SNAPSHOT_TYPE_VERTEX_SEQUENCE (0 << 4) +#define GEN6_VF_CTL_SNAPSHOT_TYPE_VERTEX_INDEX (1 << 4) +#define GEN6_VF_CTL_SKIP_INITIAL_PRIMITIVES (1 << 3) +#define GEN6_VF_CTL_MAX_PRIMITIVES_LIMIT_ENABLE (1 << 2) +#define GEN6_VF_CTL_VERTEX_RANGE_LIMIT_ENABLE (1 << 1) +#define GEN6_VF_CTL_SNAPSHOT_ENABLE (1 << 0) + +#define GEN6_VF_STRG_VAL 0x7504 +#define GEN6_VF_STR_VL_OVR 0x7508 +#define GEN6_VF_VC_OVR 0x750c +#define GEN6_VF_STR_PSKIP 0x7510 +#define GEN6_VF_MAX_PRIM 0x7514 +#define GEN6_VF_RDATA 0x7518 + +#define GEN6_VS_CTL 0x7600 +#define GEN6_VS_CTL_SNAPSHOT_COMPLETE (1 << 31) +#define GEN6_VS_CTL_SNAPSHOT_MUX_VERTEX_0 (0 << 8) +#define GEN6_VS_CTL_SNAPSHOT_MUX_VERTEX_1 (1 << 8) +#define GEN6_VS_CTL_SNAPSHOT_MUX_VALID_COUNT (2 << 8) +#define GEN6_VS_CTL_SNAPSHOT_MUX_VS_KERNEL_POINTER (3 << 8) +#define GEN6_VS_CTL_SNAPSHOT_ALL_THREADS (1 << 2) +#define GEN6_VS_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) +#define GEN6_VS_CTL_SNAPSHOT_ENABLE (1 << 0) + +#define GEN6_VS_STRG_VAL 0x7604 +#define GEN6_VS_RDATA 0x7608 + +#define GEN6_SF_CTL 0x7b00 +#define GEN6_SF_CTL_SNAPSHOT_COMPLETE (1 << 31) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_0_FF_ID (0 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_0_REL_COUNT (1 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_1_FF_ID (2 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_1_REL_COUNT (3 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_2_FF_ID (4 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_2_REL_COUNT (5 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_COUNT (6 << 8) +#define GEN6_SF_CTL_SNAPSHOT_MUX_SF_KERNEL_POINTER (7 << 8) +#define GEN6_SF_CTL_MIN_MAX_PRIMITIVE_RANGE_ENABLE (1 << 4) +#define GEN6_SF_CTL_DEBUG_CLIP_RECTANGLE_ENABLE (1 << 3) +#define GEN6_SF_CTL_SNAPSHOT_ALL_THREADS (1 << 2) +#define GEN6_SF_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) +#define GEN6_SF_CTL_SNAPSHOT_ENABLE (1 << 0) + +#define GEN6_SF_STRG_VAL 0x7b04 +#define GEN6_SF_RDATA 0x7b18 + +#define GEN6_WIZ_CTL 0x7c00 +#define GEN6_WIZ_CTL_SNAPSHOT_COMPLETE (1 << 31) +#define GEN6_WIZ_CTL_SUBSPAN_INSTANCE_SHIFT 16 +#define GEN6_WIZ_CTL_SNAPSHOT_MUX_WIZ_KERNEL_POINTER (0 << 8) +#define GEN6_WIZ_CTL_SNAPSHOT_MUX_SUBSPAN_INSTANCE (1 << 8) +#define GEN6_WIZ_CTL_SNAPSHOT_MUX_PRIMITIVE_SEQUENCE (2 << 8) +#define GEN6_WIZ_CTL_SINGLE_SUBSPAN_DISPATCH (1 << 6) +#define GEN6_WIZ_CTL_IGNORE_COLOR_SCOREBOARD_STALLS (1 << 5) +#define GEN6_WIZ_CTL_ENABLE_SUBSPAN_INSTANCE_COMPARE (1 << 4) +#define GEN6_WIZ_CTL_USE_UPSTREAM_SNAPSHOT_FLAG (1 << 3) +#define GEN6_WIZ_CTL_SNAPSHOT_ALL_THREADS (1 << 2) +#define GEN6_WIZ_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) +#define GEN6_WIZ_CTL_SNAPSHOT_ENABLE (1 << 0) + +#define GEN6_WIZ_STRG_VAL 0x7c04 +#define GEN6_WIZ_RDATA 0x7c18 + +#define GEN6_TS_CTL 0x7e00 +#define GEN6_TS_CTL_SNAPSHOT_COMPLETE (1 << 31) +#define GEN6_TS_CTL_SNAPSHOT_MESSAGE_ERROR (0 << 8) +#define GEN6_TS_CTL_SNAPSHOT_INTERFACE_DESCRIPTOR (3 << 8) +#define GEN6_TS_CTL_SNAPSHOT_ALL_CHILD_THREADS (1 << 2) +#define GEN6_TS_CTL_SNAPSHOT_ALL_ROOT_THREADS (1 << 1) +#define GEN6_TS_CTL_SNAPSHOT_ENABLE (1 << 0) + +#define GEN6_TS_STRG_VAL 0x7e04 +#define GEN6_TS_RDATA 0x7e08 + +/* TD_CTL on gen6 is 0x7000, to not break stuff which depends on this... */ +#ifndef GEN6_TD_CTL +#define GEN6_TD_CTL 0x8000 +#endif +#define GEN6_TD_CTL_MUX_SHIFT 8 +#define GEN6_TD_CTL_EXTERNAL_HALT_R0_DEBUG_MATCH (1 << 7) +#define GEN6_TD_CTL_FORCE_EXTERNAL_HALT (1 << 6) +#define GEN6_TD_CTL_EXCEPTION_MASK_OVERRIDE (1 << 5) +#define GEN6_TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE (1 << 4) +#define GEN6_TD_CTL_BREAKPOINT_ENABLE (1 << 2) +#define GEN6_TD_CTL2 0x8004 +#define GEN6_TD_CTL2_ILLEGAL_OPCODE_EXCEPTION_OVERRIDE (1 << 28) +#define GEN6_TD_CTL2_MASKSTACK_EXCEPTION_OVERRIDE (1 << 26) +#define GEN6_TD_CTL2_SOFTWARE_EXCEPTION_OVERRIDE (1 << 25) +#define GEN6_TD_CTL2_ACTIVE_THREAD_LIMIT_SHIFT 16 +#define GEN6_TD_CTL2_ACTIVE_THREAD_LIMIT_ENABLE (1 << 8) +#define GEN6_TD_CTL2_THREAD_SPAWNER_EXECUTION_MASK_ENABLE (1 << 7) +#define GEN6_TD_CTL2_WIZ_EXECUTION_MASK_ENABLE (1 << 6) +#define GEN6_TD_CTL2_SF_EXECUTION_MASK_ENABLE (1 << 5) +#define GEN6_TD_CTL2_CLIPPER_EXECUTION_MASK_ENABLE (1 << 4) +#define GEN6_TD_CTL2_GS_EXECUTION_MASK_ENABLE (1 << 3) +#define GEN6_TD_CTL2_VS_EXECUTION_MASK_ENABLE (1 << 0) +#define GEN6_TD_VF_VS_EMSK 0x8008 +#define GEN6_TD_GS_EMSK 0x800c +#define GEN6_TD_CLIP_EMSK 0x8010 +#define GEN6_TD_SF_EMSK 0x8014 +#define GEN6_TD_WIZ_EMSK 0x8018 +#define GEN6_TD_0_6_EHTRG_VAL 0x801c +#define GEN6_TD_0_7_EHTRG_VAL 0x8020 +#define GEN6_TD_0_6_EHTRG_MSK 0x8024 +#define GEN6_TD_0_7_EHTRG_MSK 0x8028 +#define GEN6_TD_RDATA 0x802c +#define GEN6_TD_TS_EMSK 0x8030 + +#define GEN6_EU_CTL 0x8800 +#define GEN6_EU_CTL_SELECT_SHIFT 16 +#define GEN6_EU_CTL_DATA_MUX_SHIFT 8 +#define GEN6_EU_ATT_0 0x8810 +#define GEN6_EU_ATT_1 0x8814 +#define GEN6_EU_ATT_DATA_0 0x8820 +#define GEN6_EU_ATT_DATA_1 0x8824 +#define GEN6_EU_ATT_CLR_0 0x8830 +#define GEN6_EU_ATT_CLR_1 0x8834 +#define GEN6_EU_RDATA 0x8840 + +/* 3D state: + */ +#define _3DOP_3DSTATE_PIPELINED 0x0 +#define _3DOP_3DSTATE_NONPIPELINED 0x1 +#define _3DOP_3DCONTROL 0x2 +#define _3DOP_3DPRIMITIVE 0x3 + +#define _3DSTATE_PIPELINED_POINTERS 0x00 +#define _3DSTATE_BINDING_TABLE_POINTERS 0x01 +#define _3DSTATE_VERTEX_BUFFERS 0x08 +#define _3DSTATE_VERTEX_ELEMENTS 0x09 +#define _3DSTATE_INDEX_BUFFER 0x0A +#define _3DSTATE_VF_STATISTICS 0x0B +#define _3DSTATE_DRAWING_RECTANGLE 0x00 +#define _3DSTATE_CONSTANT_COLOR 0x01 +#define _3DSTATE_SAMPLER_PALETTE_LOAD 0x02 +#define _3DSTATE_CHROMA_KEY 0x04 +#define _3DSTATE_DEPTH_BUFFER 0x05 +#define _3DSTATE_POLY_STIPPLE_OFFSET 0x06 +#define _3DSTATE_POLY_STIPPLE_PATTERN 0x07 +#define _3DSTATE_LINE_STIPPLE 0x08 +#define _3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP 0x09 +#define _3DCONTROL 0x00 +#define _3DPRIMITIVE 0x00 + +#define _3DPRIM_POINTLIST 0x01 +#define _3DPRIM_LINELIST 0x02 +#define _3DPRIM_LINESTRIP 0x03 +#define _3DPRIM_TRILIST 0x04 +#define _3DPRIM_TRISTRIP 0x05 +#define _3DPRIM_TRIFAN 0x06 +#define _3DPRIM_QUADLIST 0x07 +#define _3DPRIM_QUADSTRIP 0x08 +#define _3DPRIM_LINELIST_ADJ 0x09 +#define _3DPRIM_LINESTRIP_ADJ 0x0A +#define _3DPRIM_TRILIST_ADJ 0x0B +#define _3DPRIM_TRISTRIP_ADJ 0x0C +#define _3DPRIM_TRISTRIP_REVERSE 0x0D +#define _3DPRIM_POLYGON 0x0E +#define _3DPRIM_RECTLIST 0x0F +#define _3DPRIM_LINELOOP 0x10 +#define _3DPRIM_POINTLIST_BF 0x11 +#define _3DPRIM_LINESTRIP_CONT 0x12 +#define _3DPRIM_LINESTRIP_BF 0x13 +#define _3DPRIM_LINESTRIP_CONT_BF 0x14 +#define _3DPRIM_TRIFAN_NOSTIPPLE 0x15 + +#define _3DPRIM_VERTEXBUFFER_ACCESS_SEQUENTIAL 0 +#define _3DPRIM_VERTEXBUFFER_ACCESS_RANDOM 1 + +#define GEN6_ANISORATIO_2 0 +#define GEN6_ANISORATIO_4 1 +#define GEN6_ANISORATIO_6 2 +#define GEN6_ANISORATIO_8 3 +#define GEN6_ANISORATIO_10 4 +#define GEN6_ANISORATIO_12 5 +#define GEN6_ANISORATIO_14 6 +#define GEN6_ANISORATIO_16 7 + +#define GEN6_BLENDFACTOR_ONE 0x1 +#define GEN6_BLENDFACTOR_SRC_COLOR 0x2 +#define GEN6_BLENDFACTOR_SRC_ALPHA 0x3 +#define GEN6_BLENDFACTOR_DST_ALPHA 0x4 +#define GEN6_BLENDFACTOR_DST_COLOR 0x5 +#define GEN6_BLENDFACTOR_SRC_ALPHA_SATURATE 0x6 +#define GEN6_BLENDFACTOR_CONST_COLOR 0x7 +#define GEN6_BLENDFACTOR_CONST_ALPHA 0x8 +#define GEN6_BLENDFACTOR_SRC1_COLOR 0x9 +#define GEN6_BLENDFACTOR_SRC1_ALPHA 0x0A +#define GEN6_BLENDFACTOR_ZERO 0x11 +#define GEN6_BLENDFACTOR_INV_SRC_COLOR 0x12 +#define GEN6_BLENDFACTOR_INV_SRC_ALPHA 0x13 +#define GEN6_BLENDFACTOR_INV_DST_ALPHA 0x14 +#define GEN6_BLENDFACTOR_INV_DST_COLOR 0x15 +#define GEN6_BLENDFACTOR_INV_CONST_COLOR 0x17 +#define GEN6_BLENDFACTOR_INV_CONST_ALPHA 0x18 +#define GEN6_BLENDFACTOR_INV_SRC1_COLOR 0x19 +#define GEN6_BLENDFACTOR_INV_SRC1_ALPHA 0x1A + +#define GEN6_BLENDFUNCTION_ADD 0 +#define GEN6_BLENDFUNCTION_SUBTRACT 1 +#define GEN6_BLENDFUNCTION_REVERSE_SUBTRACT 2 +#define GEN6_BLENDFUNCTION_MIN 3 +#define GEN6_BLENDFUNCTION_MAX 4 + +#define GEN6_ALPHATEST_FORMAT_UNORM8 0 +#define GEN6_ALPHATEST_FORMAT_FLOAT32 1 + +#define GEN6_CHROMAKEY_KILL_ON_ANY_MATCH 0 +#define GEN6_CHROMAKEY_REPLACE_BLACK 1 + +#define GEN6_CLIP_API_OGL 0 +#define GEN6_CLIP_API_DX 1 + +#define GEN6_CLIPMODE_NORMAL 0 +#define GEN6_CLIPMODE_CLIP_ALL 1 +#define GEN6_CLIPMODE_CLIP_NON_REJECTED 2 +#define GEN6_CLIPMODE_REJECT_ALL 3 +#define GEN6_CLIPMODE_ACCEPT_ALL 4 + +#define GEN6_CLIP_NDCSPACE 0 +#define GEN6_CLIP_SCREENSPACE 1 + +#define GEN6_COMPAREFUNCTION_ALWAYS 0 +#define GEN6_COMPAREFUNCTION_NEVER 1 +#define GEN6_COMPAREFUNCTION_LESS 2 +#define GEN6_COMPAREFUNCTION_EQUAL 3 +#define GEN6_COMPAREFUNCTION_LEQUAL 4 +#define GEN6_COMPAREFUNCTION_GREATER 5 +#define GEN6_COMPAREFUNCTION_NOTEQUAL 6 +#define GEN6_COMPAREFUNCTION_GEQUAL 7 + +#define GEN6_COVERAGE_PIXELS_HALF 0 +#define GEN6_COVERAGE_PIXELS_1 1 +#define GEN6_COVERAGE_PIXELS_2 2 +#define GEN6_COVERAGE_PIXELS_4 3 + +#define GEN6_CULLMODE_BOTH 0 +#define GEN6_CULLMODE_NONE 1 +#define GEN6_CULLMODE_FRONT 2 +#define GEN6_CULLMODE_BACK 3 + +#define GEN6_DEFAULTCOLOR_R8G8B8A8_UNORM 0 +#define GEN6_DEFAULTCOLOR_R32G32B32A32_FLOAT 1 + +#define GEN6_DEPTHFORMAT_D32_FLOAT_S8X24_UINT 0 +#define GEN6_DEPTHFORMAT_D32_FLOAT 1 +#define GEN6_DEPTHFORMAT_D24_UNORM_S8_UINT 2 +#define GEN6_DEPTHFORMAT_D16_UNORM 5 + +#define GEN6_FLOATING_POINT_IEEE_754 0 +#define GEN6_FLOATING_POINT_NON_IEEE_754 1 + +#define GEN6_FRONTWINDING_CW 0 +#define GEN6_FRONTWINDING_CCW 1 + +#define GEN6_INDEX_BYTE 0 +#define GEN6_INDEX_WORD 1 +#define GEN6_INDEX_DWORD 2 + +#define GEN6_LOGICOPFUNCTION_CLEAR 0 +#define GEN6_LOGICOPFUNCTION_NOR 1 +#define GEN6_LOGICOPFUNCTION_AND_INVERTED 2 +#define GEN6_LOGICOPFUNCTION_COPY_INVERTED 3 +#define GEN6_LOGICOPFUNCTION_AND_REVERSE 4 +#define GEN6_LOGICOPFUNCTION_INVERT 5 +#define GEN6_LOGICOPFUNCTION_XOR 6 +#define GEN6_LOGICOPFUNCTION_NAND 7 +#define GEN6_LOGICOPFUNCTION_AND 8 +#define GEN6_LOGICOPFUNCTION_EQUIV 9 +#define GEN6_LOGICOPFUNCTION_NOOP 10 +#define GEN6_LOGICOPFUNCTION_OR_INVERTED 11 +#define GEN6_LOGICOPFUNCTION_COPY 12 +#define GEN6_LOGICOPFUNCTION_OR_REVERSE 13 +#define GEN6_LOGICOPFUNCTION_OR 14 +#define GEN6_LOGICOPFUNCTION_SET 15 + +#define GEN6_MAPFILTER_NEAREST 0x0 +#define GEN6_MAPFILTER_LINEAR 0x1 +#define GEN6_MAPFILTER_ANISOTROPIC 0x2 + +#define GEN6_MIPFILTER_NONE 0 +#define GEN6_MIPFILTER_NEAREST 1 +#define GEN6_MIPFILTER_LINEAR 3 + +#define GEN6_POLYGON_FRONT_FACING 0 +#define GEN6_POLYGON_BACK_FACING 1 + +#define GEN6_PREFILTER_ALWAYS 0x0 +#define GEN6_PREFILTER_NEVER 0x1 +#define GEN6_PREFILTER_LESS 0x2 +#define GEN6_PREFILTER_EQUAL 0x3 +#define GEN6_PREFILTER_LEQUAL 0x4 +#define GEN6_PREFILTER_GREATER 0x5 +#define GEN6_PREFILTER_NOTEQUAL 0x6 +#define GEN6_PREFILTER_GEQUAL 0x7 + +#define GEN6_PROVOKING_VERTEX_0 0 +#define GEN6_PROVOKING_VERTEX_1 1 +#define GEN6_PROVOKING_VERTEX_2 2 + +#define GEN6_RASTRULE_UPPER_LEFT 0 +#define GEN6_RASTRULE_UPPER_RIGHT 1 + +#define GEN6_RENDERTARGET_CLAMPRANGE_UNORM 0 +#define GEN6_RENDERTARGET_CLAMPRANGE_SNORM 1 +#define GEN6_RENDERTARGET_CLAMPRANGE_FORMAT 2 + +#define GEN6_STENCILOP_KEEP 0 +#define GEN6_STENCILOP_ZERO 1 +#define GEN6_STENCILOP_REPLACE 2 +#define GEN6_STENCILOP_INCRSAT 3 +#define GEN6_STENCILOP_DECRSAT 4 +#define GEN6_STENCILOP_INCR 5 +#define GEN6_STENCILOP_DECR 6 +#define GEN6_STENCILOP_INVERT 7 + +#define GEN6_SURFACE_MIPMAPLAYOUT_BELOW 0 +#define GEN6_SURFACE_MIPMAPLAYOUT_RIGHT 1 + +#define GEN6_SURFACEFORMAT_R32G32B32A32_FLOAT 0x000 +#define GEN6_SURFACEFORMAT_R32G32B32A32_SINT 0x001 +#define GEN6_SURFACEFORMAT_R32G32B32A32_UINT 0x002 +#define GEN6_SURFACEFORMAT_R32G32B32A32_UNORM 0x003 +#define GEN6_SURFACEFORMAT_R32G32B32A32_SNORM 0x004 +#define GEN6_SURFACEFORMAT_R64G64_FLOAT 0x005 +#define GEN6_SURFACEFORMAT_R32G32B32X32_FLOAT 0x006 +#define GEN6_SURFACEFORMAT_R32G32B32A32_SSCALED 0x007 +#define GEN6_SURFACEFORMAT_R32G32B32A32_USCALED 0x008 +#define GEN6_SURFACEFORMAT_R32G32B32_FLOAT 0x040 +#define GEN6_SURFACEFORMAT_R32G32B32_SINT 0x041 +#define GEN6_SURFACEFORMAT_R32G32B32_UINT 0x042 +#define GEN6_SURFACEFORMAT_R32G32B32_UNORM 0x043 +#define GEN6_SURFACEFORMAT_R32G32B32_SNORM 0x044 +#define GEN6_SURFACEFORMAT_R32G32B32_SSCALED 0x045 +#define GEN6_SURFACEFORMAT_R32G32B32_USCALED 0x046 +#define GEN6_SURFACEFORMAT_R16G16B16A16_UNORM 0x080 +#define GEN6_SURFACEFORMAT_R16G16B16A16_SNORM 0x081 +#define GEN6_SURFACEFORMAT_R16G16B16A16_SINT 0x082 +#define GEN6_SURFACEFORMAT_R16G16B16A16_UINT 0x083 +#define GEN6_SURFACEFORMAT_R16G16B16A16_FLOAT 0x084 +#define GEN6_SURFACEFORMAT_R32G32_FLOAT 0x085 +#define GEN6_SURFACEFORMAT_R32G32_SINT 0x086 +#define GEN6_SURFACEFORMAT_R32G32_UINT 0x087 +#define GEN6_SURFACEFORMAT_R32_FLOAT_X8X24_TYPELESS 0x088 +#define GEN6_SURFACEFORMAT_X32_TYPELESS_G8X24_UINT 0x089 +#define GEN6_SURFACEFORMAT_L32A32_FLOAT 0x08A +#define GEN6_SURFACEFORMAT_R32G32_UNORM 0x08B +#define GEN6_SURFACEFORMAT_R32G32_SNORM 0x08C +#define GEN6_SURFACEFORMAT_R64_FLOAT 0x08D +#define GEN6_SURFACEFORMAT_R16G16B16X16_UNORM 0x08E +#define GEN6_SURFACEFORMAT_R16G16B16X16_FLOAT 0x08F +#define GEN6_SURFACEFORMAT_A32X32_FLOAT 0x090 +#define GEN6_SURFACEFORMAT_L32X32_FLOAT 0x091 +#define GEN6_SURFACEFORMAT_I32X32_FLOAT 0x092 +#define GEN6_SURFACEFORMAT_R16G16B16A16_SSCALED 0x093 +#define GEN6_SURFACEFORMAT_R16G16B16A16_USCALED 0x094 +#define GEN6_SURFACEFORMAT_R32G32_SSCALED 0x095 +#define GEN6_SURFACEFORMAT_R32G32_USCALED 0x096 +#define GEN6_SURFACEFORMAT_B8G8R8A8_UNORM 0x0C0 +#define GEN6_SURFACEFORMAT_B8G8R8A8_UNORM_SRGB 0x0C1 +#define GEN6_SURFACEFORMAT_R10G10B10A2_UNORM 0x0C2 +#define GEN6_SURFACEFORMAT_R10G10B10A2_UNORM_SRGB 0x0C3 +#define GEN6_SURFACEFORMAT_R10G10B10A2_UINT 0x0C4 +#define GEN6_SURFACEFORMAT_R10G10B10_SNORM_A2_UNORM 0x0C5 +#define GEN6_SURFACEFORMAT_R8G8B8A8_UNORM 0x0C7 +#define GEN6_SURFACEFORMAT_R8G8B8A8_UNORM_SRGB 0x0C8 +#define GEN6_SURFACEFORMAT_R8G8B8A8_SNORM 0x0C9 +#define GEN6_SURFACEFORMAT_R8G8B8A8_SINT 0x0CA +#define GEN6_SURFACEFORMAT_R8G8B8A8_UINT 0x0CB +#define GEN6_SURFACEFORMAT_R16G16_UNORM 0x0CC +#define GEN6_SURFACEFORMAT_R16G16_SNORM 0x0CD +#define GEN6_SURFACEFORMAT_R16G16_SINT 0x0CE +#define GEN6_SURFACEFORMAT_R16G16_UINT 0x0CF +#define GEN6_SURFACEFORMAT_R16G16_FLOAT 0x0D0 +#define GEN6_SURFACEFORMAT_B10G10R10A2_UNORM 0x0D1 +#define GEN6_SURFACEFORMAT_B10G10R10A2_UNORM_SRGB 0x0D2 +#define GEN6_SURFACEFORMAT_R11G11B10_FLOAT 0x0D3 +#define GEN6_SURFACEFORMAT_R32_SINT 0x0D6 +#define GEN6_SURFACEFORMAT_R32_UINT 0x0D7 +#define GEN6_SURFACEFORMAT_R32_FLOAT 0x0D8 +#define GEN6_SURFACEFORMAT_R24_UNORM_X8_TYPELESS 0x0D9 +#define GEN6_SURFACEFORMAT_X24_TYPELESS_G8_UINT 0x0DA +#define GEN6_SURFACEFORMAT_L16A16_UNORM 0x0DF +#define GEN6_SURFACEFORMAT_I24X8_UNORM 0x0E0 +#define GEN6_SURFACEFORMAT_L24X8_UNORM 0x0E1 +#define GEN6_SURFACEFORMAT_A24X8_UNORM 0x0E2 +#define GEN6_SURFACEFORMAT_I32_FLOAT 0x0E3 +#define GEN6_SURFACEFORMAT_L32_FLOAT 0x0E4 +#define GEN6_SURFACEFORMAT_A32_FLOAT 0x0E5 +#define GEN6_SURFACEFORMAT_B8G8R8X8_UNORM 0x0E9 +#define GEN6_SURFACEFORMAT_B8G8R8X8_UNORM_SRGB 0x0EA +#define GEN6_SURFACEFORMAT_R8G8B8X8_UNORM 0x0EB +#define GEN6_SURFACEFORMAT_R8G8B8X8_UNORM_SRGB 0x0EC +#define GEN6_SURFACEFORMAT_R9G9B9E5_SHAREDEXP 0x0ED +#define GEN6_SURFACEFORMAT_B10G10R10X2_UNORM 0x0EE +#define GEN6_SURFACEFORMAT_L16A16_FLOAT 0x0F0 +#define GEN6_SURFACEFORMAT_R32_UNORM 0x0F1 +#define GEN6_SURFACEFORMAT_R32_SNORM 0x0F2 +#define GEN6_SURFACEFORMAT_R10G10B10X2_USCALED 0x0F3 +#define GEN6_SURFACEFORMAT_R8G8B8A8_SSCALED 0x0F4 +#define GEN6_SURFACEFORMAT_R8G8B8A8_USCALED 0x0F5 +#define GEN6_SURFACEFORMAT_R16G16_SSCALED 0x0F6 +#define GEN6_SURFACEFORMAT_R16G16_USCALED 0x0F7 +#define GEN6_SURFACEFORMAT_R32_SSCALED 0x0F8 +#define GEN6_SURFACEFORMAT_R32_USCALED 0x0F9 +#define GEN6_SURFACEFORMAT_B5G6R5_UNORM 0x100 +#define GEN6_SURFACEFORMAT_B5G6R5_UNORM_SRGB 0x101 +#define GEN6_SURFACEFORMAT_B5G5R5A1_UNORM 0x102 +#define GEN6_SURFACEFORMAT_B5G5R5A1_UNORM_SRGB 0x103 +#define GEN6_SURFACEFORMAT_B4G4R4A4_UNORM 0x104 +#define GEN6_SURFACEFORMAT_B4G4R4A4_UNORM_SRGB 0x105 +#define GEN6_SURFACEFORMAT_R8G8_UNORM 0x106 +#define GEN6_SURFACEFORMAT_R8G8_SNORM 0x107 +#define GEN6_SURFACEFORMAT_R8G8_SINT 0x108 +#define GEN6_SURFACEFORMAT_R8G8_UINT 0x109 +#define GEN6_SURFACEFORMAT_R16_UNORM 0x10A +#define GEN6_SURFACEFORMAT_R16_SNORM 0x10B +#define GEN6_SURFACEFORMAT_R16_SINT 0x10C +#define GEN6_SURFACEFORMAT_R16_UINT 0x10D +#define GEN6_SURFACEFORMAT_R16_FLOAT 0x10E +#define GEN6_SURFACEFORMAT_I16_UNORM 0x111 +#define GEN6_SURFACEFORMAT_L16_UNORM 0x112 +#define GEN6_SURFACEFORMAT_A16_UNORM 0x113 +#define GEN6_SURFACEFORMAT_L8A8_UNORM 0x114 +#define GEN6_SURFACEFORMAT_I16_FLOAT 0x115 +#define GEN6_SURFACEFORMAT_L16_FLOAT 0x116 +#define GEN6_SURFACEFORMAT_A16_FLOAT 0x117 +#define GEN6_SURFACEFORMAT_R5G5_SNORM_B6_UNORM 0x119 +#define GEN6_SURFACEFORMAT_B5G5R5X1_UNORM 0x11A +#define GEN6_SURFACEFORMAT_B5G5R5X1_UNORM_SRGB 0x11B +#define GEN6_SURFACEFORMAT_R8G8_SSCALED 0x11C +#define GEN6_SURFACEFORMAT_R8G8_USCALED 0x11D +#define GEN6_SURFACEFORMAT_R16_SSCALED 0x11E +#define GEN6_SURFACEFORMAT_R16_USCALED 0x11F +#define GEN6_SURFACEFORMAT_R8_UNORM 0x140 +#define GEN6_SURFACEFORMAT_R8_SNORM 0x141 +#define GEN6_SURFACEFORMAT_R8_SINT 0x142 +#define GEN6_SURFACEFORMAT_R8_UINT 0x143 +#define GEN6_SURFACEFORMAT_A8_UNORM 0x144 +#define GEN6_SURFACEFORMAT_I8_UNORM 0x145 +#define GEN6_SURFACEFORMAT_L8_UNORM 0x146 +#define GEN6_SURFACEFORMAT_P4A4_UNORM 0x147 +#define GEN6_SURFACEFORMAT_A4P4_UNORM 0x148 +#define GEN6_SURFACEFORMAT_R8_SSCALED 0x149 +#define GEN6_SURFACEFORMAT_R8_USCALED 0x14A +#define GEN6_SURFACEFORMAT_R1_UINT 0x181 +#define GEN6_SURFACEFORMAT_YCRCB_NORMAL 0x182 +#define GEN6_SURFACEFORMAT_YCRCB_SWAPUVY 0x183 +#define GEN6_SURFACEFORMAT_BC1_UNORM 0x186 +#define GEN6_SURFACEFORMAT_BC2_UNORM 0x187 +#define GEN6_SURFACEFORMAT_BC3_UNORM 0x188 +#define GEN6_SURFACEFORMAT_BC4_UNORM 0x189 +#define GEN6_SURFACEFORMAT_BC5_UNORM 0x18A +#define GEN6_SURFACEFORMAT_BC1_UNORM_SRGB 0x18B +#define GEN6_SURFACEFORMAT_BC2_UNORM_SRGB 0x18C +#define GEN6_SURFACEFORMAT_BC3_UNORM_SRGB 0x18D +#define GEN6_SURFACEFORMAT_MONO8 0x18E +#define GEN6_SURFACEFORMAT_YCRCB_SWAPUV 0x18F +#define GEN6_SURFACEFORMAT_YCRCB_SWAPY 0x190 +#define GEN6_SURFACEFORMAT_DXT1_RGB 0x191 +#define GEN6_SURFACEFORMAT_FXT1 0x192 +#define GEN6_SURFACEFORMAT_R8G8B8_UNORM 0x193 +#define GEN6_SURFACEFORMAT_R8G8B8_SNORM 0x194 +#define GEN6_SURFACEFORMAT_R8G8B8_SSCALED 0x195 +#define GEN6_SURFACEFORMAT_R8G8B8_USCALED 0x196 +#define GEN6_SURFACEFORMAT_R64G64B64A64_FLOAT 0x197 +#define GEN6_SURFACEFORMAT_R64G64B64_FLOAT 0x198 +#define GEN6_SURFACEFORMAT_BC4_SNORM 0x199 +#define GEN6_SURFACEFORMAT_BC5_SNORM 0x19A +#define GEN6_SURFACEFORMAT_R16G16B16_UNORM 0x19C +#define GEN6_SURFACEFORMAT_R16G16B16_SNORM 0x19D +#define GEN6_SURFACEFORMAT_R16G16B16_SSCALED 0x19E +#define GEN6_SURFACEFORMAT_R16G16B16_USCALED 0x19F + +#define GEN6_SURFACERETURNFORMAT_FLOAT32 0 +#define GEN6_SURFACERETURNFORMAT_S1 1 + +#define GEN6_SURFACE_1D 0 +#define GEN6_SURFACE_2D 1 +#define GEN6_SURFACE_3D 2 +#define GEN6_SURFACE_CUBE 3 +#define GEN6_SURFACE_BUFFER 4 +#define GEN6_SURFACE_NULL 7 + +#define GEN6_BORDER_COLOR_MODE_DEFAULT 0 +#define GEN6_BORDER_COLOR_MODE_LEGACY 1 + +#define GEN6_TEXCOORDMODE_WRAP 0 +#define GEN6_TEXCOORDMODE_MIRROR 1 +#define GEN6_TEXCOORDMODE_CLAMP 2 +#define GEN6_TEXCOORDMODE_CUBE 3 +#define GEN6_TEXCOORDMODE_CLAMP_BORDER 4 +#define GEN6_TEXCOORDMODE_MIRROR_ONCE 5 + +#define GEN6_THREAD_PRIORITY_NORMAL 0 +#define GEN6_THREAD_PRIORITY_HIGH 1 + +#define GEN6_TILEWALK_XMAJOR 0 +#define GEN6_TILEWALK_YMAJOR 1 + +#define GEN6_VERTEX_SUBPIXEL_PRECISION_8BITS 0 +#define GEN6_VERTEX_SUBPIXEL_PRECISION_4BITS 1 + +#define GEN6_VERTEXBUFFER_ACCESS_VERTEXDATA 0 +#define GEN6_VERTEXBUFFER_ACCESS_INSTANCEDATA 1 + +#define GEN6_VFCOMPONENT_NOSTORE 0 +#define GEN6_VFCOMPONENT_STORE_SRC 1 +#define GEN6_VFCOMPONENT_STORE_0 2 +#define GEN6_VFCOMPONENT_STORE_1_FLT 3 +#define GEN6_VFCOMPONENT_STORE_1_INT 4 +#define GEN6_VFCOMPONENT_STORE_VID 5 +#define GEN6_VFCOMPONENT_STORE_IID 6 +#define GEN6_VFCOMPONENT_STORE_PID 7 + + + +/* Execution Unit (EU) defines + */ + +#define GEN6_ALIGN_1 0 +#define GEN6_ALIGN_16 1 + +#define GEN6_ADDRESS_DIRECT 0 +#define GEN6_ADDRESS_REGISTER_INDIRECT_REGISTER 1 + +#define GEN6_CHANNEL_X 0 +#define GEN6_CHANNEL_Y 1 +#define GEN6_CHANNEL_Z 2 +#define GEN6_CHANNEL_W 3 + +#define GEN6_COMPRESSION_NONE 0 +#define GEN6_COMPRESSION_2NDHALF 1 +#define GEN6_COMPRESSION_COMPRESSED 2 + +#define GEN6_CONDITIONAL_NONE 0 +#define GEN6_CONDITIONAL_Z 1 +#define GEN6_CONDITIONAL_NZ 2 +#define GEN6_CONDITIONAL_EQ 1 /* Z */ +#define GEN6_CONDITIONAL_NEQ 2 /* NZ */ +#define GEN6_CONDITIONAL_G 3 +#define GEN6_CONDITIONAL_GE 4 +#define GEN6_CONDITIONAL_L 5 +#define GEN6_CONDITIONAL_LE 6 +#define GEN6_CONDITIONAL_C 7 +#define GEN6_CONDITIONAL_O 8 + +#define GEN6_DEBUG_NONE 0 +#define GEN6_DEBUG_BREAKPOINT 1 + +#define GEN6_DEPENDENCY_NORMAL 0 +#define GEN6_DEPENDENCY_NOTCLEARED 1 +#define GEN6_DEPENDENCY_NOTCHECKED 2 +#define GEN6_DEPENDENCY_DISABLE 3 + +#define GEN6_EXECUTE_1 0 +#define GEN6_EXECUTE_2 1 +#define GEN6_EXECUTE_4 2 +#define GEN6_EXECUTE_8 3 +#define GEN6_EXECUTE_16 4 +#define GEN6_EXECUTE_32 5 + +#define GEN6_HORIZONTAL_STRIDE_0 0 +#define GEN6_HORIZONTAL_STRIDE_1 1 +#define GEN6_HORIZONTAL_STRIDE_2 2 +#define GEN6_HORIZONTAL_STRIDE_4 3 + +#define GEN6_INSTRUCTION_NORMAL 0 +#define GEN6_INSTRUCTION_SATURATE 1 + +#define GEN6_MASK_ENABLE 0 +#define GEN6_MASK_DISABLE 1 + +#define GEN6_OPCODE_MOV 1 +#define GEN6_OPCODE_SEL 2 +#define GEN6_OPCODE_NOT 4 +#define GEN6_OPCODE_AND 5 +#define GEN6_OPCODE_OR 6 +#define GEN6_OPCODE_XOR 7 +#define GEN6_OPCODE_SHR 8 +#define GEN6_OPCODE_SHL 9 +#define GEN6_OPCODE_RSR 10 +#define GEN6_OPCODE_RSL 11 +#define GEN6_OPCODE_ASR 12 +#define GEN6_OPCODE_CMP 16 +#define GEN6_OPCODE_JMPI 32 +#define GEN6_OPCODE_IF 34 +#define GEN6_OPCODE_IFF 35 +#define GEN6_OPCODE_ELSE 36 +#define GEN6_OPCODE_ENDIF 37 +#define GEN6_OPCODE_DO 38 +#define GEN6_OPCODE_WHILE 39 +#define GEN6_OPCODE_BREAK 40 +#define GEN6_OPCODE_CONTINUE 41 +#define GEN6_OPCODE_HALT 42 +#define GEN6_OPCODE_MSAVE 44 +#define GEN6_OPCODE_MRESTORE 45 +#define GEN6_OPCODE_PUSH 46 +#define GEN6_OPCODE_POP 47 +#define GEN6_OPCODE_WAIT 48 +#define GEN6_OPCODE_SEND 49 +#define GEN6_OPCODE_ADD 64 +#define GEN6_OPCODE_MUL 65 +#define GEN6_OPCODE_AVG 66 +#define GEN6_OPCODE_FRC 67 +#define GEN6_OPCODE_RNDU 68 +#define GEN6_OPCODE_RNDD 69 +#define GEN6_OPCODE_RNDE 70 +#define GEN6_OPCODE_RNDZ 71 +#define GEN6_OPCODE_MAC 72 +#define GEN6_OPCODE_MACH 73 +#define GEN6_OPCODE_LZD 74 +#define GEN6_OPCODE_SAD2 80 +#define GEN6_OPCODE_SADA2 81 +#define GEN6_OPCODE_DP4 84 +#define GEN6_OPCODE_DPH 85 +#define GEN6_OPCODE_DP3 86 +#define GEN6_OPCODE_DP2 87 +#define GEN6_OPCODE_DPA2 88 +#define GEN6_OPCODE_LINE 89 +#define GEN6_OPCODE_NOP 126 + +#define GEN6_PREDICATE_NONE 0 +#define GEN6_PREDICATE_NORMAL 1 +#define GEN6_PREDICATE_ALIGN1_ANYV 2 +#define GEN6_PREDICATE_ALIGN1_ALLV 3 +#define GEN6_PREDICATE_ALIGN1_ANY2H 4 +#define GEN6_PREDICATE_ALIGN1_ALL2H 5 +#define GEN6_PREDICATE_ALIGN1_ANY4H 6 +#define GEN6_PREDICATE_ALIGN1_ALL4H 7 +#define GEN6_PREDICATE_ALIGN1_ANY8H 8 +#define GEN6_PREDICATE_ALIGN1_ALL8H 9 +#define GEN6_PREDICATE_ALIGN1_ANY16H 10 +#define GEN6_PREDICATE_ALIGN1_ALL16H 11 +#define GEN6_PREDICATE_ALIGN16_REPLICATE_X 2 +#define GEN6_PREDICATE_ALIGN16_REPLICATE_Y 3 +#define GEN6_PREDICATE_ALIGN16_REPLICATE_Z 4 +#define GEN6_PREDICATE_ALIGN16_REPLICATE_W 5 +#define GEN6_PREDICATE_ALIGN16_ANY4H 6 +#define GEN6_PREDICATE_ALIGN16_ALL4H 7 + +#define GEN6_ARCHITECTURE_REGISTER_FILE 0 +#define GEN6_GENERAL_REGISTER_FILE 1 +#define GEN6_MESSAGE_REGISTER_FILE 2 +#define GEN6_IMMEDIATE_VALUE 3 + +#define GEN6_REGISTER_TYPE_UD 0 +#define GEN6_REGISTER_TYPE_D 1 +#define GEN6_REGISTER_TYPE_UW 2 +#define GEN6_REGISTER_TYPE_W 3 +#define GEN6_REGISTER_TYPE_UB 4 +#define GEN6_REGISTER_TYPE_B 5 +#define GEN6_REGISTER_TYPE_VF 5 /* packed float vector, immediates only? */ +#define GEN6_REGISTER_TYPE_HF 6 +#define GEN6_REGISTER_TYPE_V 6 /* packed int vector, immediates only, uword dest only */ +#define GEN6_REGISTER_TYPE_F 7 + +#define GEN6_ARF_NULL 0x00 +#define GEN6_ARF_ADDRESS 0x10 +#define GEN6_ARF_ACCUMULATOR 0x20 +#define GEN6_ARF_FLAG 0x30 +#define GEN6_ARF_MASK 0x40 +#define GEN6_ARF_MASK_STACK 0x50 +#define GEN6_ARF_MASK_STACK_DEPTH 0x60 +#define GEN6_ARF_STATE 0x70 +#define GEN6_ARF_CONTROL 0x80 +#define GEN6_ARF_NOTIFICATION_COUNT 0x90 +#define GEN6_ARF_IP 0xA0 + +#define GEN6_AMASK 0 +#define GEN6_IMASK 1 +#define GEN6_LMASK 2 +#define GEN6_CMASK 3 + + + +#define GEN6_THREAD_NORMAL 0 +#define GEN6_THREAD_ATOMIC 1 +#define GEN6_THREAD_SWITCH 2 + +#define GEN6_VERTICAL_STRIDE_0 0 +#define GEN6_VERTICAL_STRIDE_1 1 +#define GEN6_VERTICAL_STRIDE_2 2 +#define GEN6_VERTICAL_STRIDE_4 3 +#define GEN6_VERTICAL_STRIDE_8 4 +#define GEN6_VERTICAL_STRIDE_16 5 +#define GEN6_VERTICAL_STRIDE_32 6 +#define GEN6_VERTICAL_STRIDE_64 7 +#define GEN6_VERTICAL_STRIDE_128 8 +#define GEN6_VERTICAL_STRIDE_256 9 +#define GEN6_VERTICAL_STRIDE_ONE_DIMENSIONAL 0xF + +#define GEN6_WIDTH_1 0 +#define GEN6_WIDTH_2 1 +#define GEN6_WIDTH_4 2 +#define GEN6_WIDTH_8 3 +#define GEN6_WIDTH_16 4 + +#define GEN6_STATELESS_BUFFER_BOUNDARY_1K 0 +#define GEN6_STATELESS_BUFFER_BOUNDARY_2K 1 +#define GEN6_STATELESS_BUFFER_BOUNDARY_4K 2 +#define GEN6_STATELESS_BUFFER_BOUNDARY_8K 3 +#define GEN6_STATELESS_BUFFER_BOUNDARY_16K 4 +#define GEN6_STATELESS_BUFFER_BOUNDARY_32K 5 +#define GEN6_STATELESS_BUFFER_BOUNDARY_64K 6 +#define GEN6_STATELESS_BUFFER_BOUNDARY_128K 7 +#define GEN6_STATELESS_BUFFER_BOUNDARY_256K 8 +#define GEN6_STATELESS_BUFFER_BOUNDARY_512K 9 +#define GEN6_STATELESS_BUFFER_BOUNDARY_1M 10 +#define GEN6_STATELESS_BUFFER_BOUNDARY_2M 11 + +#define GEN6_POLYGON_FACING_FRONT 0 +#define GEN6_POLYGON_FACING_BACK 1 + +#define GEN6_MESSAGE_TARGET_NULL 0 +#define GEN6_MESSAGE_TARGET_MATH 1 +#define GEN6_MESSAGE_TARGET_SAMPLER 2 +#define GEN6_MESSAGE_TARGET_GATEWAY 3 +#define GEN6_MESSAGE_TARGET_DATAPORT_READ 4 +#define GEN6_MESSAGE_TARGET_DATAPORT_WRITE 5 +#define GEN6_MESSAGE_TARGET_URB 6 +#define GEN6_MESSAGE_TARGET_THREAD_SPAWNER 7 + +#define GEN6_SAMPLER_RETURN_FORMAT_FLOAT32 0 +#define GEN6_SAMPLER_RETURN_FORMAT_UINT32 2 +#define GEN6_SAMPLER_RETURN_FORMAT_SINT32 3 + +#define GEN6_SAMPLER_MESSAGE_SIMD8_SAMPLE 0 +#define GEN6_SAMPLER_MESSAGE_SIMD16_SAMPLE 0 +#define GEN6_SAMPLER_MESSAGE_SIMD16_SAMPLE_BIAS 0 +#define GEN6_SAMPLER_MESSAGE_SIMD8_KILLPIX 1 +#define GEN6_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_LOD 1 +#define GEN6_SAMPLER_MESSAGE_SIMD16_SAMPLE_LOD 1 +#define GEN6_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_GRADIENTS 2 +#define GEN6_SAMPLER_MESSAGE_SIMD8_SAMPLE_GRADIENTS 2 +#define GEN6_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_COMPARE 0 +#define GEN6_SAMPLER_MESSAGE_SIMD16_SAMPLE_COMPARE 2 +#define GEN6_SAMPLER_MESSAGE_SIMD4X2_RESINFO 2 +#define GEN6_SAMPLER_MESSAGE_SIMD8_RESINFO 2 +#define GEN6_SAMPLER_MESSAGE_SIMD16_RESINFO 2 +#define GEN6_SAMPLER_MESSAGE_SIMD4X2_LD 3 +#define GEN6_SAMPLER_MESSAGE_SIMD8_LD 3 +#define GEN6_SAMPLER_MESSAGE_SIMD16_LD 3 + +#define GEN6_DATAPORT_OWORD_BLOCK_1_OWORDLOW 0 +#define GEN6_DATAPORT_OWORD_BLOCK_1_OWORDHIGH 1 +#define GEN6_DATAPORT_OWORD_BLOCK_2_OWORDS 2 +#define GEN6_DATAPORT_OWORD_BLOCK_4_OWORDS 3 +#define GEN6_DATAPORT_OWORD_BLOCK_8_OWORDS 4 + +#define GEN6_DATAPORT_OWORD_DUAL_BLOCK_1OWORD 0 +#define GEN6_DATAPORT_OWORD_DUAL_BLOCK_4OWORDS 2 + +#define GEN6_DATAPORT_DWORD_SCATTERED_BLOCK_8DWORDS 2 +#define GEN6_DATAPORT_DWORD_SCATTERED_BLOCK_16DWORDS 3 + +#define GEN6_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ 0 +#define GEN6_DATAPORT_READ_MESSAGE_OWORD_DUAL_BLOCK_READ 1 +#define GEN6_DATAPORT_READ_MESSAGE_DWORD_BLOCK_READ 2 +#define GEN6_DATAPORT_READ_MESSAGE_DWORD_SCATTERED_READ 3 + +#define GEN6_DATAPORT_READ_TARGET_DATA_CACHE 0 +#define GEN6_DATAPORT_READ_TARGET_RENDER_CACHE 1 +#define GEN6_DATAPORT_READ_TARGET_SAMPLER_CACHE 2 + +#define GEN6_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE 0 +#define GEN6_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED 1 +#define GEN6_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN01 2 +#define GEN6_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN23 3 +#define GEN6_DATAPORT_RENDER_TARGET_WRITE_SIMD8_SINGLE_SOURCE_SUBSPAN01 4 + +#define GEN6_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE 0 +#define GEN6_DATAPORT_WRITE_MESSAGE_OWORD_DUAL_BLOCK_WRITE 1 +#define GEN6_DATAPORT_WRITE_MESSAGE_DWORD_BLOCK_WRITE 2 +#define GEN6_DATAPORT_WRITE_MESSAGE_DWORD_SCATTERED_WRITE 3 +#define GEN6_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE 4 +#define GEN6_DATAPORT_WRITE_MESSAGE_STREAMED_VERTEX_BUFFER_WRITE 5 +#define GEN6_DATAPORT_WRITE_MESSAGE_FLUSH_RENDER_CACHE 7 + +#define GEN6_MATH_FUNCTION_INV 1 +#define GEN6_MATH_FUNCTION_LOG 2 +#define GEN6_MATH_FUNCTION_EXP 3 +#define GEN6_MATH_FUNCTION_SQRT 4 +#define GEN6_MATH_FUNCTION_RSQ 5 +#define GEN6_MATH_FUNCTION_SIN 6 /* was 7 */ +#define GEN6_MATH_FUNCTION_COS 7 /* was 8 */ +#define GEN6_MATH_FUNCTION_SINCOS 8 /* was 6 */ +#define GEN6_MATH_FUNCTION_TAN 9 +#define GEN6_MATH_FUNCTION_POW 10 +#define GEN6_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER 11 +#define GEN6_MATH_FUNCTION_INT_DIV_QUOTIENT 12 +#define GEN6_MATH_FUNCTION_INT_DIV_REMAINDER 13 + +#define GEN6_MATH_INTEGER_UNSIGNED 0 +#define GEN6_MATH_INTEGER_SIGNED 1 + +#define GEN6_MATH_PRECISION_FULL 0 +#define GEN6_MATH_PRECISION_PARTIAL 1 + +#define GEN6_MATH_SATURATE_NONE 0 +#define GEN6_MATH_SATURATE_SATURATE 1 + +#define GEN6_MATH_DATA_VECTOR 0 +#define GEN6_MATH_DATA_SCALAR 1 + +#define GEN6_URB_OPCODE_WRITE 0 + +#define GEN6_URB_SWIZZLE_NONE 0 +#define GEN6_URB_SWIZZLE_INTERLEAVE 1 +#define GEN6_URB_SWIZZLE_TRANSPOSE 2 + +#define GEN6_SCRATCH_SPACE_SIZE_1K 0 +#define GEN6_SCRATCH_SPACE_SIZE_2K 1 +#define GEN6_SCRATCH_SPACE_SIZE_4K 2 +#define GEN6_SCRATCH_SPACE_SIZE_8K 3 +#define GEN6_SCRATCH_SPACE_SIZE_16K 4 +#define GEN6_SCRATCH_SPACE_SIZE_32K 5 +#define GEN6_SCRATCH_SPACE_SIZE_64K 6 +#define GEN6_SCRATCH_SPACE_SIZE_128K 7 +#define GEN6_SCRATCH_SPACE_SIZE_256K 8 +#define GEN6_SCRATCH_SPACE_SIZE_512K 9 +#define GEN6_SCRATCH_SPACE_SIZE_1M 10 +#define GEN6_SCRATCH_SPACE_SIZE_2M 11 + +/* The hardware supports two different modes for border color. The + * default (OpenGL) mode uses floating-point color channels, while the + * legacy mode uses 4 bytes. + * + * More significantly, the legacy mode respects the components of the + * border color for channels not present in the source, (whereas the + * default mode will ignore the border color's alpha channel and use + * alpha==1 for an RGB source, for example). + * + * The legacy mode matches the semantics specified by the Render + * extension. + */ +struct gen6_sampler_default_border_color { + float color[4]; +}; + +struct gen6_sampler_legacy_border_color { + uint8_t color[4]; +}; + +struct gen6_sampler_state { + struct { + uint32_t shadow_function:3; + uint32_t lod_bias:11; + uint32_t min_filter:3; + uint32_t mag_filter:3; + uint32_t mip_filter:2; + uint32_t base_level:5; + uint32_t pad:1; + uint32_t lod_preclamp:1; + uint32_t border_color_mode:1; + uint32_t pad0:1; + uint32_t disable:1; + } ss0; + + struct { + uint32_t r_wrap_mode:3; + uint32_t t_wrap_mode:3; + uint32_t s_wrap_mode:3; + uint32_t pad:3; + uint32_t max_lod:10; + uint32_t min_lod:10; + } ss1; + + struct { + uint32_t border_color; + } ss2; + + struct { + uint32_t pad:19; + uint32_t max_aniso:3; + uint32_t chroma_key_mode:1; + uint32_t chroma_key_index:2; + uint32_t chroma_key_enable:1; + uint32_t monochrome_filter_width:3; + uint32_t monochrome_filter_height:3; + } ss3; +}; + +struct gen6_blend_state { + struct { + uint32_t dest_blend_factor:5; + uint32_t source_blend_factor:5; + uint32_t pad3:1; + uint32_t blend_func:3; + uint32_t pad2:1; + uint32_t ia_dest_blend_factor:5; + uint32_t ia_source_blend_factor:5; + uint32_t pad1:1; + uint32_t ia_blend_func:3; + uint32_t pad0:1; + uint32_t ia_blend_enable:1; + uint32_t blend_enable:1; + } blend0; + + struct { + uint32_t post_blend_clamp_enable:1; + uint32_t pre_blend_clamp_enable:1; + uint32_t clamp_range:2; + uint32_t pad0:4; + uint32_t x_dither_offset:2; + uint32_t y_dither_offset:2; + uint32_t dither_enable:1; + uint32_t alpha_test_func:3; + uint32_t alpha_test_enable:1; + uint32_t pad1:1; + uint32_t logic_op_func:4; + uint32_t logic_op_enable:1; + uint32_t pad2:1; + uint32_t write_disable_b:1; + uint32_t write_disable_g:1; + uint32_t write_disable_r:1; + uint32_t write_disable_a:1; + uint32_t pad3:1; + uint32_t alpha_to_coverage_dither:1; + uint32_t alpha_to_one:1; + uint32_t alpha_to_coverage:1; + } blend1; +}; + +struct gen6_color_calc_state { + struct { + uint32_t alpha_test_format:1; + uint32_t pad0:14; + uint32_t round_disable:1; + uint32_t bf_stencil_ref:8; + uint32_t stencil_ref:8; + } cc0; + + union { + float alpha_ref_f; + struct { + uint32_t ui:8; + uint32_t pad0:24; + } alpha_ref_fi; + } cc1; + + float constant_r; + float constant_g; + float constant_b; + float constant_a; +}; + +struct gen6_depth_stencil_state { + struct { + uint32_t pad0:3; + uint32_t bf_stencil_pass_depth_pass_op:3; + uint32_t bf_stencil_pass_depth_fail_op:3; + uint32_t bf_stencil_fail_op:3; + uint32_t bf_stencil_func:3; + uint32_t bf_stencil_enable:1; + uint32_t pad1:2; + uint32_t stencil_write_enable:1; + uint32_t stencil_pass_depth_pass_op:3; + uint32_t stencil_pass_depth_fail_op:3; + uint32_t stencil_fail_op:3; + uint32_t stencil_func:3; + uint32_t stencil_enable:1; + } ds0; + + struct { + uint32_t bf_stencil_write_mask:8; + uint32_t bf_stencil_test_mask:8; + uint32_t stencil_write_mask:8; + uint32_t stencil_test_mask:8; + } ds1; + + struct { + uint32_t pad0:26; + uint32_t depth_write_enable:1; + uint32_t depth_test_func:3; + uint32_t pad1:1; + uint32_t depth_test_enable:1; + } ds2; +}; + +struct gen6_surface_state { + struct { + uint32_t cube_pos_z:1; + uint32_t cube_neg_z:1; + uint32_t cube_pos_y:1; + uint32_t cube_neg_y:1; + uint32_t cube_pos_x:1; + uint32_t cube_neg_x:1; + uint32_t pad:3; + uint32_t render_cache_read_mode:1; + uint32_t mipmap_layout_mode:1; + uint32_t vert_line_stride_ofs:1; + uint32_t vert_line_stride:1; + uint32_t color_blend:1; + uint32_t writedisable_blue:1; + uint32_t writedisable_green:1; + uint32_t writedisable_red:1; + uint32_t writedisable_alpha:1; + uint32_t surface_format:9; + uint32_t data_return_format:1; + uint32_t pad0:1; + uint32_t surface_type:3; + } ss0; + + struct { + uint32_t base_addr; + } ss1; + + struct { + uint32_t render_target_rotation:2; + uint32_t mip_count:4; + uint32_t width:13; + uint32_t height:13; + } ss2; + + struct { + uint32_t tile_walk:1; + uint32_t tiled_surface:1; + uint32_t pad:1; + uint32_t pitch:18; + uint32_t depth:11; + } ss3; + + struct { + uint32_t pad:19; + uint32_t min_array_elt:9; + uint32_t min_lod:4; + } ss4; + + struct { + uint32_t pad:20; + uint32_t y_offset:4; + uint32_t pad2:1; + uint32_t x_offset:7; + } ss5; +}; + +struct gen6_cc_viewport { + float min_depth; + float max_depth; +}; + +typedef enum { + SAMPLER_FILTER_NEAREST = 0, + SAMPLER_FILTER_BILINEAR, + FILTER_COUNT +} sampler_filter_t; + +typedef enum { + SAMPLER_EXTEND_NONE = 0, + SAMPLER_EXTEND_REPEAT, + SAMPLER_EXTEND_PAD, + SAMPLER_EXTEND_REFLECT, + EXTEND_COUNT +} sampler_extend_t; + +#endif diff --git a/lib/gen7_render.h b/lib/gen7_render.h new file mode 100644 index 00000000..6cd94753 --- /dev/null +++ b/lib/gen7_render.h @@ -0,0 +1,222 @@ +#ifndef GEN7_RENDER_H +#define GEN7_RENDER_H + +#include "gen6_render.h" + +#define GEN7_3DSTATE_URB_VS (0x7830 << 16) +#define GEN7_3DSTATE_URB_HS (0x7831 << 16) +#define GEN7_3DSTATE_URB_DS (0x7832 << 16) +#define GEN7_3DSTATE_URB_GS (0x7833 << 16) + +#define GEN6_3DSTATE_SCISSOR_STATE_POINTERS GEN6_3D(3, 0, 0xf) +#define GEN7_3DSTATE_CLEAR_PARAMS GEN6_3D(3, 0, 0x04) +#define GEN7_3DSTATE_DEPTH_BUFFER GEN6_3D(3, 0, 0x05) +#define GEN7_3DSTATE_STENCIL_BUFFER GEN6_3D(3, 0, 0x06) +#define GEN7_3DSTATE_HIER_DEPTH_BUFFER GEN6_3D(3, 0, 0x07) + +#define GEN7_3DSTATE_GS GEN6_3D(3, 0, 0x11) +#define GEN7_3DSTATE_CONSTANT_GS GEN6_3D(3, 0, 0x16) +#define GEN7_3DSTATE_CONSTANT_HS GEN6_3D(3, 0, 0x19) +#define GEN7_3DSTATE_CONSTANT_DS GEN6_3D(3, 0, 0x1a) +#define GEN7_3DSTATE_HS GEN6_3D(3, 0, 0x1b) +#define GEN7_3DSTATE_TE GEN6_3D(3, 0, 0x1c) +#define GEN7_3DSTATE_DS GEN6_3D(3, 0, 0x1d) +#define GEN7_3DSTATE_STREAMOUT GEN6_3D(3, 0, 0x1e) +#define GEN7_3DSTATE_SBE GEN6_3D(3, 0, 0x1f) +#define GEN7_3DSTATE_PS GEN6_3D(3, 0, 0x20) +#define GEN7_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP \ + GEN6_3D(3, 0, 0x21) +#define GEN7_3DSTATE_VIEWPORT_STATE_POINTERS_CC GEN6_3D(3, 0, 0x23) +#define GEN7_3DSTATE_BLEND_STATE_POINTERS GEN6_3D(3, 0, 0x24) +#define GEN7_3DSTATE_DS_STATE_POINTERS GEN6_3D(3, 0, 0x25) +#define GEN7_3DSTATE_BINDING_TABLE_POINTERS_VS GEN6_3D(3, 0, 0x26) +#define GEN7_3DSTATE_BINDING_TABLE_POINTERS_HS GEN6_3D(3, 0, 0x27) +#define GEN7_3DSTATE_BINDING_TABLE_POINTERS_DS GEN6_3D(3, 0, 0x28) +#define GEN7_3DSTATE_BINDING_TABLE_POINTERS_GS GEN6_3D(3, 0, 0x29) +#define GEN7_3DSTATE_BINDING_TABLE_POINTERS_PS GEN6_3D(3, 0, 0x2a) + +#define GEN7_3DSTATE_SAMPLER_STATE_POINTERS_VS GEN6_3D(3, 0, 0x2b) +#define GEN7_3DSTATE_SAMPLER_STATE_POINTERS_HS GEN6_3D(3, 0, 0x2c) +#define GEN7_3DSTATE_SAMPLER_STATE_POINTERS_DS GEN6_3D(3, 0, 0x2d) +#define GEN7_3DSTATE_SAMPLER_STATE_POINTERS_GS GEN6_3D(3, 0, 0x2e) +#define GEN7_3DSTATE_SAMPLER_STATE_POINTERS_PS GEN6_3D(3, 0, 0x2f) + +#define GEN7_3DSTATE_PUSH_CONSTANT_ALLOC_VS GEN6_3D(3, 1, 0x12) +#define GEN7_3DSTATE_PUSH_CONSTANT_ALLOC_HS GEN6_3D(3, 1, 0x13) +#define GEN7_3DSTATE_PUSH_CONSTANT_ALLOC_DS GEN6_3D(3, 1, 0x14) +#define GEN7_3DSTATE_PUSH_CONSTANT_ALLOC_GS GEN6_3D(3, 1, 0x15) +#define GEN7_3DSTATE_PUSH_CONSTANT_ALLOC_PS GEN6_3D(3, 1, 0x16) + +/* Some random bits that we care about */ +#define GEN7_VB0_BUFFER_ADDR_MOD_EN (1 << 14) +#define GEN7_WM_DISPATCH_ENABLE (1 << 29) +#define GEN7_3DSTATE_PS_PERSPECTIVE_PIXEL_BARYCENTRIC (1 << 11) +#define GEN7_3DSTATE_PS_ATTRIBUTE_ENABLED (1 << 10) + +/* Random shifts */ +#define GEN7_3DSTATE_WM_MAX_THREADS_SHIFT 24 +#define HSW_3DSTATE_WM_MAX_THREADS_SHIFT 23 + +/* Shamelessly ripped from mesa */ +struct gen7_surface_state +{ + struct { + uint32_t cube_pos_z:1; + uint32_t cube_neg_z:1; + uint32_t cube_pos_y:1; + uint32_t cube_neg_y:1; + uint32_t cube_pos_x:1; + uint32_t cube_neg_x:1; + uint32_t pad2:2; + uint32_t render_cache_read_write:1; + uint32_t pad1:1; + uint32_t surface_array_spacing:1; + uint32_t vert_line_stride_ofs:1; + uint32_t vert_line_stride:1; + uint32_t tile_walk:1; + uint32_t tiled_surface:1; + uint32_t horizontal_alignment:1; + uint32_t vertical_alignment:2; + uint32_t surface_format:9; /**< BRW_SURFACEFORMAT_x */ + uint32_t pad0:1; + uint32_t is_array:1; + uint32_t surface_type:3; /**< BRW_SURFACE_1D/2D/3D/CUBE */ + } ss0; + + struct { + uint32_t base_addr; + } ss1; + + struct { + uint32_t width:14; + uint32_t pad1:2; + uint32_t height:14; + uint32_t pad0:2; + } ss2; + + struct { + uint32_t pitch:18; + uint32_t pad:3; + uint32_t depth:11; + } ss3; + + struct { + uint32_t multisample_position_palette_index:3; + uint32_t num_multisamples:3; + uint32_t multisampled_surface_storage_format:1; + uint32_t render_target_view_extent:11; + uint32_t min_array_elt:11; + uint32_t rotation:2; + uint32_t pad0:1; + } ss4; + + struct { + uint32_t mip_count:4; + uint32_t min_lod:4; + uint32_t pad1:12; + uint32_t y_offset:4; + uint32_t pad0:1; + uint32_t x_offset:7; + } ss5; + + struct { + uint32_t pad; /* Multisample Control Surface stuff */ + } ss6; + + struct { + uint32_t resource_min_lod:12; + + /* Only on Haswell */ + uint32_t pad0:4; + uint32_t shader_chanel_select_a:3; + uint32_t shader_chanel_select_b:3; + uint32_t shader_chanel_select_g:3; + uint32_t shader_chanel_select_r:3; + + uint32_t alpha_clear_color:1; + uint32_t blue_clear_color:1; + uint32_t green_clear_color:1; + uint32_t red_clear_color:1; + } ss7; +}; + +struct gen7_sampler_state +{ + struct + { + uint32_t aniso_algorithm:1; + uint32_t lod_bias:13; + uint32_t min_filter:3; + uint32_t mag_filter:3; + uint32_t mip_filter:2; + uint32_t base_level:5; + uint32_t pad1:1; + uint32_t lod_preclamp:1; + uint32_t default_color_mode:1; + uint32_t pad0:1; + uint32_t disable:1; + } ss0; + + struct + { + uint32_t cube_control_mode:1; + uint32_t shadow_function:3; + uint32_t pad:4; + uint32_t max_lod:12; + uint32_t min_lod:12; + } ss1; + + struct + { + uint32_t pad:5; + uint32_t default_color_pointer:27; + } ss2; + + struct + { + uint32_t r_wrap_mode:3; + uint32_t t_wrap_mode:3; + uint32_t s_wrap_mode:3; + uint32_t pad:1; + uint32_t non_normalized_coord:1; + uint32_t trilinear_quality:2; + uint32_t address_round:6; + uint32_t max_aniso:3; + uint32_t chroma_key_mode:1; + uint32_t chroma_key_index:2; + uint32_t chroma_key_enable:1; + uint32_t pad0:6; + } ss3; +}; + +struct gen7_sf_clip_viewport { + struct { + float m00; + float m11; + float m22; + float m30; + float m31; + float m32; + } viewport; + + uint32_t pad0[2]; + + struct { + float xmin; + float xmax; + float ymin; + float ymax; + } guardband; + + float pad1[4]; +}; + +struct gen6_scissor_rect +{ + uint32_t xmin:16; + uint32_t ymin:16; + uint32_t xmax:16; + uint32_t ymax:16; +}; + +#endif diff --git a/lib/i830_reg.h b/lib/i830_reg.h new file mode 100644 index 00000000..93d03cf3 --- /dev/null +++ b/lib/i830_reg.h @@ -0,0 +1,805 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 _I830_REG_H_ +#define _I830_REG_H_ + +#define I830_SET_FIELD( var, mask, value ) (var &= ~(mask), var |= value) + +/* Flush */ +#define MI_FLUSH (0x04<<23) +#define MI_FLUSH_DW (0x26<<23) + +#define MI_WRITE_DIRTY_STATE (1<<4) +#define MI_END_SCENE (1<<3) +#define MI_GLOBAL_SNAPSHOT_COUNT_RESET (1<<3) +#define MI_INHIBIT_RENDER_CACHE_FLUSH (1<<2) +#define MI_STATE_INSTRUCTION_CACHE_FLUSH (1<<1) +#define MI_INVALIDATE_MAP_CACHE (1<<0) +/* broadwater flush bits */ +#define BRW_MI_GLOBAL_SNAPSHOT_RESET (1 << 3) + +#define MI_BATCH_BUFFER_END (0xA << 23) + +/* Noop */ +#define MI_NOOP 0x00 +#define MI_NOOP_WRITE_ID (1<<22) +#define MI_NOOP_ID_MASK (1<<22 - 1) + +/* Wait for Events */ +#define MI_WAIT_FOR_EVENT (0x03<<23) +#define MI_WAIT_FOR_PIPEB_SVBLANK (1<<18) +#define MI_WAIT_FOR_PIPEA_SVBLANK (1<<17) +#define MI_WAIT_FOR_OVERLAY_FLIP (1<<16) +#define MI_WAIT_FOR_PIPEB_VBLANK (1<<7) +#define MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW (1<<5) +#define MI_WAIT_FOR_PIPEA_VBLANK (1<<3) +#define MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW (1<<1) + +/* Set the scan line for MI_WAIT_FOR_PIPE?_SCAN_LINE_WINDOW */ +#define MI_LOAD_SCAN_LINES_INCL (0x12<<23) +#define MI_LOAD_SCAN_LINES_DISPLAY_PIPEA (0) +#define MI_LOAD_SCAN_LINES_DISPLAY_PIPEB (0x1<<20) + +/* BLT commands */ +#define COLOR_BLT_CMD ((2<<29)|(0x40<<22)|(0x3)) +#define COLOR_BLT_WRITE_ALPHA (1<<21) +#define COLOR_BLT_WRITE_RGB (1<<20) + +#define XY_COLOR_BLT_CMD ((2<<29)|(0x50<<22)|(0x4)) +#define XY_COLOR_BLT_WRITE_ALPHA (1<<21) +#define XY_COLOR_BLT_WRITE_RGB (1<<20) +#define XY_COLOR_BLT_TILED (1<<11) + +#define XY_SETUP_CLIP_BLT_CMD ((2<<29)|(3<<22)|1) + +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) +#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) +#define XY_SRC_COPY_BLT_DST_TILED (1<<11) + +#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|0x4) +#define SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define SRC_COPY_BLT_WRITE_RGB (1<<20) + +#define XY_PAT_BLT_IMMEDIATE ((2<<29)|(0x72<<22)) + +#define XY_MONO_PAT_BLT_CMD ((0x2<<29)|(0x52<<22)|0x7) +#define XY_MONO_PAT_VERT_SEED ((1<<10)|(1<<9)|(1<<8)) +#define XY_MONO_PAT_HORT_SEED ((1<<14)|(1<<13)|(1<<12)) +#define XY_MONO_PAT_BLT_WRITE_ALPHA (1<<21) +#define XY_MONO_PAT_BLT_WRITE_RGB (1<<20) + +#define XY_MONO_SRC_BLT_CMD ((0x2<<29)|(0x54<<22)|(0x6)) +#define XY_MONO_SRC_BLT_WRITE_ALPHA (1<<21) +#define XY_MONO_SRC_BLT_WRITE_RGB (1<<20) + +#define CMD_3D (0x3<<29) + +#define PRIM3D_INLINE (CMD_3D | (0x1f<<24)) +#define PRIM3D_TRILIST (0x0<<18) +#define PRIM3D_TRISTRIP (0x1<<18) +#define PRIM3D_TRISTRIP_RVRSE (0x2<<18) +#define PRIM3D_TRIFAN (0x3<<18) +#define PRIM3D_POLY (0x4<<18) +#define PRIM3D_LINELIST (0x5<<18) +#define PRIM3D_LINESTRIP (0x6<<18) +#define PRIM3D_RECTLIST (0x7<<18) +#define PRIM3D_POINTLIST (0x8<<18) +#define PRIM3D_DIB (0x9<<18) +#define PRIM3D_CLEAR_RECT (0xa<<18) +#define PRIM3D_ZONE_INIT (0xd<<18) +#define PRIM3D_MASK (0x1f<<18) + +#define _3DSTATE_AA_CMD (CMD_3D | (0x06<<24)) +#define AA_LINE_ECAAR_WIDTH_ENABLE (1<<16) +#define AA_LINE_ECAAR_WIDTH_0_5 0 +#define AA_LINE_ECAAR_WIDTH_1_0 (1<<14) +#define AA_LINE_ECAAR_WIDTH_2_0 (2<<14) +#define AA_LINE_ECAAR_WIDTH_4_0 (3<<14) +#define AA_LINE_REGION_WIDTH_ENABLE (1<<8) +#define AA_LINE_REGION_WIDTH_0_5 0 +#define AA_LINE_REGION_WIDTH_1_0 (1<<6) +#define AA_LINE_REGION_WIDTH_2_0 (2<<6) +#define AA_LINE_REGION_WIDTH_4_0 (3<<6) +#define AA_LINE_ENABLE ((1<<1) | 1) +#define AA_LINE_DISABLE (1<<1) + +#define _3DSTATE_BUF_INFO_CMD (CMD_3D | (0x1d<<24) | (0x8e<<16) | 1) +/* Dword 1 */ +#define BUF_3D_ID_COLOR_BACK (0x3<<24) +#define BUF_3D_ID_DEPTH (0x7<<24) +#define BUF_3D_USE_FENCE (1<<23) +#define BUF_3D_TILED_SURFACE (1<<22) +#define BUF_3D_TILE_WALK_X 0 +#define BUF_3D_TILE_WALK_Y (1<<21) +#define BUF_3D_PITCH(x) (((x)/4)<<2) +/* Dword 2 */ +#define BUF_3D_ADDR(x) ((x) & ~0x3) + +#define _3DSTATE_COLOR_FACTOR_CMD (CMD_3D | (0x1d<<24) | (0x1<<16)) + +#define _3DSTATE_COLOR_FACTOR_N_CMD(stage) (CMD_3D | (0x1d<<24) | \ + ((0x90+(stage))<<16)) + +#define _3DSTATE_CONST_BLEND_COLOR_CMD (CMD_3D | (0x1d<<24) | (0x88<<16)) + +#define _3DSTATE_DFLT_DIFFUSE_CMD (CMD_3D | (0x1d<<24) | (0x99<<16)) + +#define _3DSTATE_DFLT_SPEC_CMD (CMD_3D | (0x1d<<24) | (0x9a<<16)) + +#define _3DSTATE_DFLT_Z_CMD (CMD_3D | (0x1d<<24) | (0x98<<16)) + +#define _3DSTATE_DST_BUF_VARS_CMD (CMD_3D | (0x1d<<24) | (0x85<<16)) +/* Dword 1 */ +#define DSTORG_HORT_BIAS(x) ((x)<<20) +#define DSTORG_VERT_BIAS(x) ((x)<<16) +#define COLOR_4_2_2_CHNL_WRT_ALL 0 +#define COLOR_4_2_2_CHNL_WRT_Y (1<<12) +#define COLOR_4_2_2_CHNL_WRT_CR (2<<12) +#define COLOR_4_2_2_CHNL_WRT_CB (3<<12) +#define COLOR_4_2_2_CHNL_WRT_CRCB (4<<12) +#define COLR_BUF_8BIT 0 +#define COLR_BUF_RGB555 (1<<8) +#define COLR_BUF_RGB565 (2<<8) +#define COLR_BUF_ARGB8888 (3<<8) +#define COLR_BUF_ARGB4444 (8<<8) +#define COLR_BUF_ARGB1555 (9<<8) +#define DEPTH_IS_Z 0 +#define DEPTH_IS_W (1<<6) +#define DEPTH_FRMT_16_FIXED 0 +#define DEPTH_FRMT_16_FLOAT (1<<2) +#define DEPTH_FRMT_24_FIXED_8_OTHER (2<<2) +#define DEPTH_FRMT_24_FLOAT_8_OTHER (3<<2) +#define VERT_LINE_STRIDE_1 (1<<1) +#define VERT_LINE_STRIDE_0 0 +#define VERT_LINE_STRIDE_OFS_1 1 +#define VERT_LINE_STRIDE_OFS_0 0 + +#define _3DSTATE_DRAW_RECT_CMD (CMD_3D|(0x1d<<24)|(0x80<<16)|3) +/* Dword 1 */ +#define DRAW_RECT_DIS_DEPTH_OFS (1<<30) +#define DRAW_DITHER_OFS_X(x) ((x)<<26) +#define DRAW_DITHER_OFS_Y(x) ((x)<<24) +/* Dword 2 */ +#define DRAW_YMIN(x) ((x)<<16) +#define DRAW_XMIN(x) (x) +/* Dword 3 */ +#define DRAW_YMAX(x) ((x)<<16) +#define DRAW_XMAX(x) (x) +/* Dword 4 */ +#define DRAW_YORG(x) ((x)<<16) +#define DRAW_XORG(x) (x) + +#define _3DSTATE_ENABLES_1_CMD (CMD_3D|(0x3<<24)) +#define ENABLE_LOGIC_OP_MASK ((1<<23)|(1<<22)) +#define ENABLE_LOGIC_OP ((1<<23)|(1<<22)) +#define DISABLE_LOGIC_OP (1<<23) +#define ENABLE_STENCIL_TEST ((1<<21)|(1<<20)) +#define DISABLE_STENCIL_TEST (1<<21) +#define ENABLE_DEPTH_BIAS ((1<<11)|(1<<10)) +#define DISABLE_DEPTH_BIAS (1<<11) +#define ENABLE_SPEC_ADD_MASK ((1<<9)|(1<<8)) +#define ENABLE_SPEC_ADD ((1<<9)|(1<<8)) +#define DISABLE_SPEC_ADD (1<<9) +#define ENABLE_DIS_FOG_MASK ((1<<7)|(1<<6)) +#define ENABLE_FOG ((1<<7)|(1<<6)) +#define DISABLE_FOG (1<<7) +#define ENABLE_DIS_ALPHA_TEST_MASK ((1<<5)|(1<<4)) +#define ENABLE_ALPHA_TEST ((1<<5)|(1<<4)) +#define DISABLE_ALPHA_TEST (1<<5) +#define ENABLE_DIS_CBLEND_MASK ((1<<3)|(1<<2)) +#define ENABLE_COLOR_BLEND ((1<<3)|(1<<2)) +#define DISABLE_COLOR_BLEND (1<<3) +#define ENABLE_DIS_DEPTH_TEST_MASK ((1<<1)|1) +#define ENABLE_DEPTH_TEST ((1<<1)|1) +#define DISABLE_DEPTH_TEST (1<<1) + +/* _3DSTATE_ENABLES_2, p138 */ +#define _3DSTATE_ENABLES_2_CMD (CMD_3D|(0x4<<24)) +#define ENABLE_STENCIL_WRITE ((1<<21)|(1<<20)) +#define DISABLE_STENCIL_WRITE (1<<21) +#define ENABLE_TEX_CACHE ((1<<17)|(1<<16)) +#define DISABLE_TEX_CACHE (1<<17) +#define ENABLE_DITHER ((1<<9)|(1<<8)) +#define DISABLE_DITHER (1<<9) +#define ENABLE_COLOR_MASK (1<<10) +#define WRITEMASK_ALPHA (1<<7) +#define WRITEMASK_ALPHA_SHIFT 7 +#define WRITEMASK_RED (1<<6) +#define WRITEMASK_RED_SHIFT 6 +#define WRITEMASK_GREEN (1<<5) +#define WRITEMASK_GREEN_SHIFT 5 +#define WRITEMASK_BLUE (1<<4) +#define WRITEMASK_BLUE_SHIFT 4 +#define WRITEMASK_MASK ((1<<4)|(1<<5)|(1<<6)|(1<<7)) +#define ENABLE_COLOR_WRITE ((1<<3)|(1<<2)) +#define DISABLE_COLOR_WRITE (1<<3) +#define ENABLE_DIS_DEPTH_WRITE_MASK 0x3 +#define ENABLE_DEPTH_WRITE ((1<<1)|1) +#define DISABLE_DEPTH_WRITE (1<<1) + +/* _3DSTATE_FOG_COLOR, p139 */ +#define _3DSTATE_FOG_COLOR_CMD (CMD_3D|(0x15<<24)) +#define FOG_COLOR_RED(x) ((x)<<16) +#define FOG_COLOR_GREEN(x) ((x)<<8) +#define FOG_COLOR_BLUE(x) (x) + +/* _3DSTATE_FOG_MODE, p140 */ +#define _3DSTATE_FOG_MODE_CMD (CMD_3D|(0x1d<<24)|(0x89<<16)|2) +/* Dword 1 */ +#define FOGFUNC_ENABLE (1<<31) +#define FOGFUNC_VERTEX 0 +#define FOGFUNC_PIXEL_EXP (1<<28) +#define FOGFUNC_PIXEL_EXP2 (2<<28) +#define FOGFUNC_PIXEL_LINEAR (3<<28) +#define FOGSRC_INDEX_Z (1<<27) +#define FOGSRC_INDEX_W ((1<<27)|(1<<25)) +#define FOG_LINEAR_CONST (1<<24) +#define FOG_CONST_1(x) ((x)<<4) +#define ENABLE_FOG_DENSITY (1<<23) +/* Dword 2 */ +#define FOG_CONST_2(x) (x) +/* Dword 3 */ +#define FOG_DENSITY(x) (x) + +/* _3DSTATE_INDEPENDENT_ALPHA_BLEND, p142 */ +#define _3DSTATE_INDPT_ALPHA_BLEND_CMD (CMD_3D|(0x0b<<24)) +#define ENABLE_INDPT_ALPHA_BLEND ((1<<23)|(1<<22)) +#define DISABLE_INDPT_ALPHA_BLEND (1<<23) +#define ALPHA_BLENDFUNC_MASK 0x3f0000 +#define ENABLE_ALPHA_BLENDFUNC (1<<21) +#define ABLENDFUNC_ADD 0 +#define ABLENDFUNC_SUB (1<<16) +#define ABLENDFUNC_RVSE_SUB (2<<16) +#define ABLENDFUNC_MIN (3<<16) +#define ABLENDFUNC_MAX (4<<16) +#define SRC_DST_ABLEND_MASK 0xfff +#define ENABLE_SRC_ABLEND_FACTOR (1<<11) +#define SRC_ABLEND_FACT(x) ((x)<<6) +#define ENABLE_DST_ABLEND_FACTOR (1<<5) +#define DST_ABLEND_FACT(x) (x) + +#define BLENDFACTOR_ZERO 0x01 +#define BLENDFACTOR_ONE 0x02 +#define BLENDFACTOR_SRC_COLR 0x03 +#define BLENDFACTOR_INV_SRC_COLR 0x04 +#define BLENDFACTOR_SRC_ALPHA 0x05 +#define BLENDFACTOR_INV_SRC_ALPHA 0x06 +#define BLENDFACTOR_DST_ALPHA 0x07 +#define BLENDFACTOR_INV_DST_ALPHA 0x08 +#define BLENDFACTOR_DST_COLR 0x09 +#define BLENDFACTOR_INV_DST_COLR 0x0a +#define BLENDFACTOR_SRC_ALPHA_SATURATE 0x0b +#define BLENDFACTOR_CONST_COLOR 0x0c +#define BLENDFACTOR_INV_CONST_COLOR 0x0d +#define BLENDFACTOR_CONST_ALPHA 0x0e +#define BLENDFACTOR_INV_CONST_ALPHA 0x0f +#define BLENDFACTOR_MASK 0x0f + +/* _3DSTATE_MAP_BLEND_ARG, p152 */ +#define _3DSTATE_MAP_BLEND_ARG_CMD(stage) (CMD_3D|(0x0e<<24)|((stage)<<20)) + +#define TEXPIPE_COLOR 0 +#define TEXPIPE_ALPHA (1<<18) +#define TEXPIPE_KILL (2<<18) +#define TEXBLEND_ARG0 0 +#define TEXBLEND_ARG1 (1<<15) +#define TEXBLEND_ARG2 (2<<15) +#define TEXBLEND_ARG3 (3<<15) +#define TEXBLENDARG_MODIFY_PARMS (1<<6) +#define TEXBLENDARG_REPLICATE_ALPHA (1<<5) +#define TEXBLENDARG_INV_ARG (1<<4) +#define TEXBLENDARG_ONE 0 +#define TEXBLENDARG_FACTOR 0x01 +#define TEXBLENDARG_ACCUM 0x02 +#define TEXBLENDARG_DIFFUSE 0x03 +#define TEXBLENDARG_SPEC 0x04 +#define TEXBLENDARG_CURRENT 0x05 +#define TEXBLENDARG_TEXEL0 0x06 +#define TEXBLENDARG_TEXEL1 0x07 +#define TEXBLENDARG_TEXEL2 0x08 +#define TEXBLENDARG_TEXEL3 0x09 +#define TEXBLENDARG_FACTOR_N 0x0e + +/* _3DSTATE_MAP_BLEND_OP, p155 */ +#define _3DSTATE_MAP_BLEND_OP_CMD(stage) (CMD_3D|(0x0d<<24)|((stage)<<20)) +#if 0 +# define TEXPIPE_COLOR 0 +# define TEXPIPE_ALPHA (1<<18) +# define TEXPIPE_KILL (2<<18) +#endif +#define ENABLE_TEXOUTPUT_WRT_SEL (1<<17) +#define TEXOP_OUTPUT_CURRENT 0 +#define TEXOP_OUTPUT_ACCUM (1<<15) +#define ENABLE_TEX_CNTRL_STAGE ((1<<12)|(1<<11)) +#define DISABLE_TEX_CNTRL_STAGE (1<<12) +#define TEXOP_SCALE_SHIFT 9 +#define TEXOP_SCALE_1X (0 << TEXOP_SCALE_SHIFT) +#define TEXOP_SCALE_2X (1 << TEXOP_SCALE_SHIFT) +#define TEXOP_SCALE_4X (2 << TEXOP_SCALE_SHIFT) +#define TEXOP_MODIFY_PARMS (1<<8) +#define TEXOP_LAST_STAGE (1<<7) +#define TEXBLENDOP_KILLPIXEL 0x02 +#define TEXBLENDOP_ARG1 0x01 +#define TEXBLENDOP_ARG2 0x02 +#define TEXBLENDOP_MODULATE 0x03 +#define TEXBLENDOP_ADD 0x06 +#define TEXBLENDOP_ADDSIGNED 0x07 +#define TEXBLENDOP_BLEND 0x08 +#define TEXBLENDOP_BLEND_AND_ADD 0x09 +#define TEXBLENDOP_SUBTRACT 0x0a +#define TEXBLENDOP_DOT3 0x0b +#define TEXBLENDOP_DOT4 0x0c +#define TEXBLENDOP_MODULATE_AND_ADD 0x0d +#define TEXBLENDOP_MODULATE_2X_AND_ADD 0x0e +#define TEXBLENDOP_MODULATE_4X_AND_ADD 0x0f + +/* _3DSTATE_MAP_BUMP_TABLE, p160 TODO */ +/* _3DSTATE_MAP_COLOR_CHROMA_KEY, p161 TODO */ + +#define _3DSTATE_MAP_COORD_TRANSFORM ((3<<29)|(0x1d<<24)|(0x8c<<16)) +#define DISABLE_TEX_TRANSFORM (1<<28) +#define TEXTURE_SET(x) (x<<29) + +#define _3DSTATE_VERTEX_TRANSFORM ((3<<29)|(0x1d<<24)|(0x8b<<16)) +#define DISABLE_VIEWPORT_TRANSFORM (1<<31) +#define DISABLE_PERSPECTIVE_DIVIDE (1<<29) + +/* _3DSTATE_MAP_COORD_SET_BINDINGS, p162 */ +#define _3DSTATE_MAP_COORD_SETBIND_CMD (CMD_3D|(0x1d<<24)|(0x02<<16)) +#define TEXBIND_MASK3 ((1<<15)|(1<<14)|(1<<13)|(1<<12)) +#define TEXBIND_MASK2 ((1<<11)|(1<<10)|(1<<9)|(1<<8)) +#define TEXBIND_MASK1 ((1<<7)|(1<<6)|(1<<5)|(1<<4)) +#define TEXBIND_MASK0 ((1<<3)|(1<<2)|(1<<1)|1) + +#define TEXBIND_SET3(x) ((x)<<12) +#define TEXBIND_SET2(x) ((x)<<8) +#define TEXBIND_SET1(x) ((x)<<4) +#define TEXBIND_SET0(x) (x) + +#define TEXCOORDSRC_KEEP 0 +#define TEXCOORDSRC_DEFAULT 0x01 +#define TEXCOORDSRC_VTXSET_0 0x08 +#define TEXCOORDSRC_VTXSET_1 0x09 +#define TEXCOORDSRC_VTXSET_2 0x0a +#define TEXCOORDSRC_VTXSET_3 0x0b +#define TEXCOORDSRC_VTXSET_4 0x0c +#define TEXCOORDSRC_VTXSET_5 0x0d +#define TEXCOORDSRC_VTXSET_6 0x0e +#define TEXCOORDSRC_VTXSET_7 0x0f + +#define MAP_UNIT(unit) ((unit)<<16) +#define MAP_UNIT_MASK (0x7<<16) + +/* _3DSTATE_MAP_COORD_SETS, p164 */ +#define _3DSTATE_MAP_COORD_SET_CMD (CMD_3D|(0x1c<<24)|(0x01<<19)) +#define TEXCOORD_SET(n) ((n)<<16) +#define ENABLE_TEXCOORD_PARAMS (1<<15) +#define TEXCOORDS_ARE_NORMAL (1<<14) +#define TEXCOORDS_ARE_IN_TEXELUNITS 0 +#define TEXCOORDTYPE_CARTESIAN 0 +#define TEXCOORDTYPE_HOMOGENEOUS (1<<11) +#define TEXCOORDTYPE_VECTOR (2<<11) +#define TEXCOORDTYPE_MASK (0x7<<11) +#define ENABLE_ADDR_V_CNTL (1<<7) +#define ENABLE_ADDR_U_CNTL (1<<3) +#define TEXCOORD_ADDR_V_MODE(x) ((x)<<4) +#define TEXCOORD_ADDR_U_MODE(x) (x) +#define TEXCOORDMODE_WRAP 0 +#define TEXCOORDMODE_MIRROR 1 +#define TEXCOORDMODE_CLAMP 2 +#define TEXCOORDMODE_WRAP_SHORTEST 3 +#define TEXCOORDMODE_CLAMP_BORDER 4 +#define TEXCOORD_ADDR_V_MASK 0x70 +#define TEXCOORD_ADDR_U_MASK 0x7 + +/* _3DSTATE_MAP_CUBE, p168 TODO */ +#define _3DSTATE_MAP_CUBE (CMD_3D|(0x1c<<24)|(0x0a<<19)) +#define CUBE_NEGX_ENABLE (1<<5) +#define CUBE_POSX_ENABLE (1<<4) +#define CUBE_NEGY_ENABLE (1<<3) +#define CUBE_POSY_ENABLE (1<<2) +#define CUBE_NEGZ_ENABLE (1<<1) +#define CUBE_POSZ_ENABLE (1<<0) + +#define _3DSTATE_MAP_INFO_CMD (CMD_3D|(0x1d<<24)|(0x0<<16)|3) +#define TEXMAP_INDEX(x) ((x)<<28) +#define MAP_SURFACE_8BIT (1<<24) +#define MAP_SURFACE_16BIT (2<<24) +#define MAP_SURFACE_32BIT (3<<24) +#define MAP_FORMAT_2D (0) +#define MAP_FORMAT_3D_CUBE (1<<11) + +/* _3DSTATE_MODES_1, p190 */ +#define _3DSTATE_MODES_1_CMD (CMD_3D|(0x08<<24)) +#define BLENDFUNC_MASK 0x3f0000 +#define ENABLE_COLR_BLND_FUNC (1<<21) +#define BLENDFUNC_ADD 0 +#define BLENDFUNC_SUB (1<<16) +#define BLENDFUNC_RVRSE_SUB (2<<16) +#define BLENDFUNC_MIN (3<<16) +#define BLENDFUNC_MAX (4<<16) +#define SRC_DST_BLND_MASK 0xfff +#define ENABLE_SRC_BLND_FACTOR (1<<11) +#define ENABLE_DST_BLND_FACTOR (1<<5) +#define SRC_BLND_FACT(x) ((x)<<6) +#define DST_BLND_FACT(x) (x) + +/* _3DSTATE_MODES_2, p192 */ +#define _3DSTATE_MODES_2_CMD (CMD_3D|(0x0f<<24)) +#define ENABLE_GLOBAL_DEPTH_BIAS (1<<22) +#define GLOBAL_DEPTH_BIAS(x) ((x)<<14) +#define ENABLE_ALPHA_TEST_FUNC (1<<13) +#define ENABLE_ALPHA_REF_VALUE (1<<8) +#define ALPHA_TEST_FUNC(x) ((x)<<9) +#define ALPHA_REF_VALUE(x) (x) + +#define ALPHA_TEST_REF_MASK 0x3fff + +/* _3DSTATE_MODES_3, p193 */ +#define _3DSTATE_MODES_3_CMD (CMD_3D|(0x02<<24)) +#define DEPTH_TEST_FUNC_MASK 0x1f0000 +#define ENABLE_DEPTH_TEST_FUNC (1<<20) +/* Uses COMPAREFUNC */ +#define DEPTH_TEST_FUNC(x) ((x)<<16) +#define ENABLE_ALPHA_SHADE_MODE (1<<11) +#define ENABLE_FOG_SHADE_MODE (1<<9) +#define ENABLE_SPEC_SHADE_MODE (1<<7) +#define ENABLE_COLOR_SHADE_MODE (1<<5) +#define ALPHA_SHADE_MODE(x) ((x)<<10) +#define FOG_SHADE_MODE(x) ((x)<<8) +#define SPEC_SHADE_MODE(x) ((x)<<6) +#define COLOR_SHADE_MODE(x) ((x)<<4) +#define CULLMODE_MASK 0xf +#define ENABLE_CULL_MODE (1<<3) +#define CULLMODE_BOTH 0 +#define CULLMODE_NONE 1 +#define CULLMODE_CW 2 +#define CULLMODE_CCW 3 + +#define SHADE_MODE_LINEAR 0 +#define SHADE_MODE_FLAT 0x1 + +/* _3DSTATE_MODES_4, p195 */ +#define _3DSTATE_MODES_4_CMD (CMD_3D|(0x16<<24)) +#define ENABLE_LOGIC_OP_FUNC (1<<23) +#define LOGIC_OP_FUNC(x) ((x)<<18) +#define LOGICOP_MASK ((1<<18)|(1<<19)|(1<<20)|(1<<21)) +#define LOGICOP_CLEAR 0 +#define LOGICOP_NOR 0x1 +#define LOGICOP_AND_INV 0x2 +#define LOGICOP_COPY_INV 0x3 +#define LOGICOP_AND_RVRSE 0x4 +#define LOGICOP_INV 0x5 +#define LOGICOP_XOR 0x6 +#define LOGICOP_NAND 0x7 +#define LOGICOP_AND 0x8 +#define LOGICOP_EQUIV 0x9 +#define LOGICOP_NOOP 0xa +#define LOGICOP_OR_INV 0xb +#define LOGICOP_COPY 0xc +#define LOGICOP_OR_RVRSE 0xd +#define LOGICOP_OR 0xe +#define LOGICOP_SET 0xf +#define MODE4_ENABLE_STENCIL_TEST_MASK ((1<<17)|(0xff00)) +#define ENABLE_STENCIL_TEST_MASK (1<<17) +#define STENCIL_TEST_MASK(x) ((x)<<8) +#define MODE4_ENABLE_STENCIL_WRITE_MASK ((1<<16)|(0x00ff)) +#define ENABLE_STENCIL_WRITE_MASK (1<<16) +#define STENCIL_WRITE_MASK(x) ((x)&0xff) + +/* _3DSTATE_MODES_5, p196 */ +#define _3DSTATE_MODES_5_CMD (CMD_3D|(0x0c<<24)) +#define ENABLE_SPRITE_POINT_TEX (1<<23) +#define SPRITE_POINT_TEX_ON (1<<22) +#define SPRITE_POINT_TEX_OFF 0 +#define FLUSH_RENDER_CACHE (1<<18) +#define FLUSH_TEXTURE_CACHE (1<<16) +#define FIXED_LINE_WIDTH_MASK 0xfc00 +#define ENABLE_FIXED_LINE_WIDTH (1<<15) +#define FIXED_LINE_WIDTH(x) ((x)<<10) +#define FIXED_POINT_WIDTH_MASK 0x3ff +#define ENABLE_FIXED_POINT_WIDTH (1<<9) +#define FIXED_POINT_WIDTH(x) (x) + +/* _3DSTATE_RASTERIZATION_RULES, p198 */ +#define _3DSTATE_RASTER_RULES_CMD (CMD_3D|(0x07<<24)) +#define ENABLE_POINT_RASTER_RULE (1<<15) +#define OGL_POINT_RASTER_RULE (1<<13) +#define ENABLE_LINE_STRIP_PROVOKE_VRTX (1<<8) +#define ENABLE_TRI_FAN_PROVOKE_VRTX (1<<5) +#define ENABLE_TRI_STRIP_PROVOKE_VRTX (1<<2) +#define LINE_STRIP_PROVOKE_VRTX(x) ((x)<<6) +#define TRI_FAN_PROVOKE_VRTX(x) ((x)<<3) +#define TRI_STRIP_PROVOKE_VRTX(x) (x) + +/* _3DSTATE_SCISSOR_ENABLE, p200 */ +#define _3DSTATE_SCISSOR_ENABLE_CMD (CMD_3D|(0x1c<<24)|(0x10<<19)) +#define ENABLE_SCISSOR_RECT ((1<<1) | 1) +#define DISABLE_SCISSOR_RECT (1<<1) + +/* _3DSTATE_SCISSOR_RECTANGLE_0, p201 */ +#define _3DSTATE_SCISSOR_RECT_0_CMD (CMD_3D|(0x1d<<24)|(0x81<<16)|1) +/* Dword 1 */ +#define SCISSOR_RECT_0_YMIN(x) ((x)<<16) +#define SCISSOR_RECT_0_XMIN(x) (x) +/* Dword 2 */ +#define SCISSOR_RECT_0_YMAX(x) ((x)<<16) +#define SCISSOR_RECT_0_XMAX(x) (x) + +/* _3DSTATE_STENCIL_TEST, p202 */ +#define _3DSTATE_STENCIL_TEST_CMD (CMD_3D|(0x09<<24)) +#define ENABLE_STENCIL_PARMS (1<<23) +#define STENCIL_OPS_MASK (0xffc000) +#define STENCIL_FAIL_OP(x) ((x)<<20) +#define STENCIL_PASS_DEPTH_FAIL_OP(x) ((x)<<17) +#define STENCIL_PASS_DEPTH_PASS_OP(x) ((x)<<14) + +#define ENABLE_STENCIL_TEST_FUNC_MASK ((1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)) +#define ENABLE_STENCIL_TEST_FUNC (1<<13) +/* Uses COMPAREFUNC */ +#define STENCIL_TEST_FUNC(x) ((x)<<9) +#define STENCIL_REF_VALUE_MASK ((1<<8)|0xff) +#define ENABLE_STENCIL_REF_VALUE (1<<8) +#define STENCIL_REF_VALUE(x) (x) + +/* _3DSTATE_VERTEX_FORMAT, p204 */ +#define _3DSTATE_VFT0_CMD (CMD_3D|(0x05<<24)) +#define VFT0_POINT_WIDTH (1<<12) +#define VFT0_TEX_COUNT_MASK (7<<8) +#define VFT0_TEX_COUNT_SHIFT 8 +#define VFT0_TEX_COUNT(x) ((x)<<8) +#define VFT0_SPEC (1<<7) +#define VFT0_DIFFUSE (1<<6) +#define VFT0_DEPTH_OFFSET (1<<5) +#define VFT0_XYZ (1<<1) +#define VFT0_XYZW (2<<1) +#define VFT0_XY (3<<1) +#define VFT0_XYW (4<<1) +#define VFT0_XYZW_MASK (7<<1) + +/* _3DSTATE_VERTEX_FORMAT_2, p206 */ +#define _3DSTATE_VERTEX_FORMAT_2_CMD (CMD_3D|(0x0a<<24)) +#define VFT1_TEX7_FMT(x) ((x)<<14) +#define VFT1_TEX6_FMT(x) ((x)<<12) +#define VFT1_TEX5_FMT(x) ((x)<<10) +#define VFT1_TEX4_FMT(x) ((x)<<8) +#define VFT1_TEX3_FMT(x) ((x)<<6) +#define VFT1_TEX2_FMT(x) ((x)<<4) +#define VFT1_TEX1_FMT(x) ((x)<<2) +#define VFT1_TEX0_FMT(x) (x) +#define VFT1_TEX0_MASK 3 +#define VFT1_TEX1_SHIFT 2 +#define TEXCOORDFMT_2D 0 +#define TEXCOORDFMT_3D 1 +#define TEXCOORDFMT_4D 2 +#define TEXCOORDFMT_1D 3 + +/*New stuff picked up along the way */ + +#define MLC_LOD_BIAS_MASK ((1<<7)-1) + +/* _3DSTATE_VERTEX_TRANSFORM, p207 */ +#define _3DSTATE_VERTEX_TRANS_CMD (CMD_3D|(0x1d<<24)|(0x8b<<16)|0) +#define _3DSTATE_VERTEX_TRANS_MTX_CMD (CMD_3D|(0x1d<<24)|(0x8b<<16)|6) +/* Dword 1 */ +#define ENABLE_VIEWPORT_TRANSFORM ((1<<31)|(1<<30)) +#define DISABLE_VIEWPORT_TRANSFORM (1<<31) +#define ENABLE_PERSP_DIVIDE ((1<<29)|(1<<28)) +#define DISABLE_PERSP_DIVIDE (1<<29) +#define VRTX_TRANS_LOAD_MATRICES 0x7421 +#define VRTX_TRANS_NO_LOAD_MATRICES 0x0000 +/* Dword 2 -> 7 are matrix elements */ + +/* _3DSTATE_W_STATE, p209 */ +#define _3DSTATE_W_STATE_CMD (CMD_3D|(0x1d<<24)|(0x8d<<16)|1) +/* Dword 1 */ +#define MAGIC_W_STATE_DWORD1 0x00000008 +/* Dword 2 */ +#define WFAR_VALUE(x) (x) + +/* Stipple command, carried over from the i810, apparently: + */ +#define _3DSTATE_STIPPLE (CMD_3D|(0x1d<<24)|(0x83<<16)) +#define ST1_ENABLE (1<<16) +#define ST1_MASK (0xffff) + +#define _3DSTATE_LOAD_STATE_IMMEDIATE_1 (CMD_3D|(0x1d<<24)|(0x04<<16)) +#define I1_LOAD_S(n) (1<<((n)+4)) +#define S3_POINT_WIDTH_SHIFT 23 +#define S3_LINE_WIDTH_SHIFT 19 +#define S3_ALPHA_SHADE_MODE_SHIFT 18 +#define S3_FOG_SHADE_MODE_SHIFT 17 +#define S3_SPEC_SHADE_MODE_SHIFT 16 +#define S3_COLOR_SHADE_MODE_SHIFT 15 +#define S3_CULL_MODE_SHIFT 13 +#define S3_CULLMODE_BOTH (0) +#define S3_CULLMODE_NONE (1<<13) +#define S3_CULLMODE_CW (2<<13) +#define S3_CULLMODE_CCW (3<<13) +#define S3_POINT_WIDTH_PRESENT (1<<12) +#define S3_SPEC_FOG_PRESENT (1<<11) +#define S3_DIFFUSE_PRESENT (1<<10) +#define S3_DEPTH_OFFSET_PRESENT (1<<9) +#define S3_POSITION_SHIFT 6 +#define S3_VERTEXHAS_XYZ (1<<6) +#define S3_VERTEXHAS_XYZW (2<<6) +#define S3_VERTEXHAS_XY (3<<6) +#define S3_VERTEXHAS_XYW (4<<6) +#define S3_ENABLE_SPEC_ADD (1<<5) +#define S3_ENABLE_FOG (1<<4) +#define S3_ENABLE_LOCAL_DEPTH_BIAS (1<<3) +#define S3_ENABLE_SPRITE_POINT (1<<1) +#define S3_ENABLE_ANTIALIASING 1 +#define S8_ENABLE_ALPHA_TEST (1<<31) +#define S8_ALPHA_TEST_FUNC_SHIFT 28 +#define S8_ALPHA_REFVALUE_SHIFT 20 +#define S8_ENABLE_DEPTH_TEST (1<<19) +#define S8_DEPTH_TEST_FUNC_SHIFT 16 +#define S8_ENABLE_COLOR_BLEND (1<<15) +#define S8_COLOR_BLEND_FUNC_SHIFT 12 +#define S8_BLENDFUNC_ADD (0) +#define S8_BLENDFUNC_SUB (1<<12) +#define S8_BLENDFUNC_RVRSE_SUB (2<<12) +#define S8_BLENDFUNC_MIN (3<<12) +#define S8_BLENDFUNC_MAX (4<<12) +#define S8_SRC_BLEND_FACTOR_SHIFT 8 +#define S8_DST_BLEND_FACTOR_SHIFT 4 +#define S8_ENABLE_DEPTH_BUFFER_WRITE (1<<3) +#define S8_ENABLE_COLOR_BUFFER_WRITE (1<<2) + +#define _3DSTATE_LOAD_STATE_IMMEDIATE_2 (CMD_3D|(0x1d<<24)|(0x03<<16)) +#define LOAD_TEXTURE_MAP(x) (1<<((x)+11)) +#define LOAD_TEXTURE_BLEND_STAGE(x) (1<<((x)+7)) +#define LOAD_GLOBAL_COLOR_FACTOR (1<<6) + +#define TM0S0_ADDRESS_MASK 0xfffffffc +#define TM0S0_USE_FENCE (1<<1) + +#define TM0S1_HEIGHT_SHIFT 21 +#define TM0S1_WIDTH_SHIFT 10 +#define TM0S1_PALETTE_SELECT (1<<9) +#define TM0S1_MAPSURF_FORMAT_MASK (0x7 << 6) +#define TM0S1_MAPSURF_FORMAT_SHIFT 6 +#define MAPSURF_8BIT_INDEXED (0<<6) +#define MAPSURF_8BIT (1<<6) +#define MAPSURF_16BIT (2<<6) +#define MAPSURF_32BIT (3<<6) +#define MAPSURF_411 (4<<6) +#define MAPSURF_422 (5<<6) +#define MAPSURF_COMPRESSED (6<<6) +#define MAPSURF_4BIT_INDEXED (7<<6) +#define TM0S1_MT_FORMAT_MASK (0x7 << 3) +#define TM0S1_MT_FORMAT_SHIFT 3 +#define MT_4BIT_IDX_ARGB8888 (7<<3) /* SURFACE_4BIT_INDEXED */ +#define MT_8BIT_IDX_RGB565 (0<<3) /* SURFACE_8BIT_INDEXED */ +#define MT_8BIT_IDX_ARGB1555 (1<<3) +#define MT_8BIT_IDX_ARGB4444 (2<<3) +#define MT_8BIT_IDX_AY88 (3<<3) +#define MT_8BIT_IDX_ABGR8888 (4<<3) +#define MT_8BIT_IDX_BUMP_88DVDU (5<<3) +#define MT_8BIT_IDX_BUMP_655LDVDU (6<<3) +#define MT_8BIT_IDX_ARGB8888 (7<<3) +#define MT_8BIT_I8 (0<<3) /* SURFACE_8BIT */ +#define MT_8BIT_L8 (1<<3) +#define MT_8BIT_A8 (4<<3) +#define MT_16BIT_RGB565 (0<<3) /* SURFACE_16BIT */ +#define MT_16BIT_ARGB1555 (1<<3) +#define MT_16BIT_ARGB4444 (2<<3) +#define MT_16BIT_AY88 (3<<3) +#define MT_16BIT_DIB_ARGB1555_8888 (4<<3) +#define MT_16BIT_BUMP_88DVDU (5<<3) +#define MT_16BIT_BUMP_655LDVDU (6<<3) +#define MT_16BIT_DIB_RGB565_8888 (7<<3) +#define MT_32BIT_ARGB8888 (0<<3) /* SURFACE_32BIT */ +#define MT_32BIT_ABGR8888 (1<<3) +#define MT_32BIT_XRGB8888 (2<<3) +#define MT_32BIT_XBGR8888 (3<<3) +#define MT_32BIT_BUMP_XLDVDU_8888 (6<<3) +#define MT_32BIT_DIB_8888 (7<<3) +#define MT_411_YUV411 (0<<3) /* SURFACE_411 */ +#define MT_422_YCRCB_SWAPY (0<<3) /* SURFACE_422 */ +#define MT_422_YCRCB_NORMAL (1<<3) +#define MT_422_YCRCB_SWAPUV (2<<3) +#define MT_422_YCRCB_SWAPUVY (3<<3) +#define MT_COMPRESS_DXT1 (0<<3) /* SURFACE_COMPRESSED */ +#define MT_COMPRESS_DXT2_3 (1<<3) +#define MT_COMPRESS_DXT4_5 (2<<3) +#define MT_COMPRESS_FXT1 (3<<3) +#define TM0S1_COLORSPACE_CONVERSION (1 << 2) +#define TM0S1_TILED_SURFACE (1 << 1) +#define TM0S1_TILE_WALK (1 << 0) + +#define TM0S2_PITCH_SHIFT 21 +#define TM0S2_CUBE_FACE_ENA_SHIFT 15 +#define TM0S2_CUBE_FACE_ENA_MASK (1<<15) +#define TM0S2_MAP_FORMAT (1<<14) +#define TM0S2_MAP_2D (0<<14) +#define TM0S2_MAP_3D_CUBE (1<<14) +#define TM0S2_VERTICAL_LINE_STRIDE (1<<13) +#define TM0S2_VERITCAL_LINE_STRIDE_OFF (1<<12) +#define TM0S2_OUTPUT_CHAN_SHIFT 10 +#define TM0S2_OUTPUT_CHAN_MASK (3<<10) + +#define TM0S3_MIP_FILTER_MASK (0x3<<30) +#define TM0S3_MIP_FILTER_SHIFT 30 +#define MIPFILTER_NONE 0 +#define MIPFILTER_NEAREST 1 +#define MIPFILTER_LINEAR 3 +#define TM0S3_MAG_FILTER_MASK (0x3<<28) +#define TM0S3_MAG_FILTER_SHIFT 28 +#define TM0S3_MIN_FILTER_MASK (0x3<<26) +#define TM0S3_MIN_FILTER_SHIFT 26 +#define FILTER_NEAREST 0 +#define FILTER_LINEAR 1 +#define FILTER_ANISOTROPIC 2 + +#define TM0S3_LOD_BIAS_SHIFT 17 +#define TM0S3_LOD_BIAS_MASK (0x1ff<<17) +#define TM0S3_MAX_MIP_SHIFT 9 +#define TM0S3_MAX_MIP_MASK (0xff<<9) +#define TM0S3_MIN_MIP_SHIFT 3 +#define TM0S3_MIN_MIP_MASK (0x3f<<3) +#define TM0S3_KILL_PIXEL (1<<2) +#define TM0S3_KEYED_FILTER (1<<1) +#define TM0S3_CHROMA_KEY (1<<0) + +/* _3DSTATE_MAP_TEXEL_STREAM, p188 */ +#define _3DSTATE_MAP_TEX_STREAM_CMD (CMD_3D|(0x1c<<24)|(0x05<<19)) +#define DISABLE_TEX_STREAM_BUMP (1<<12) +#define ENABLE_TEX_STREAM_BUMP ((1<<12)|(1<<11)) +#define TEX_MODIFY_UNIT_0 0 +#define TEX_MODIFY_UNIT_1 (1<<8) +#define ENABLE_TEX_STREAM_COORD_SET (1<<7) +#define TEX_STREAM_COORD_SET(x) ((x)<<4) +#define ENABLE_TEX_STREAM_MAP_IDX (1<<3) +#define TEX_STREAM_MAP_IDX(x) (x) + +#define FLUSH_MAP_CACHE (1<<0) + +#define _3DSTATE_MAP_FILTER_CMD (CMD_3D|(0x1c<<24)|(0x02<<19)) +#define FILTER_TEXMAP_INDEX(x) ((x) << 16) +#define MAG_MODE_FILTER_ENABLE (1 << 5) +#define MIN_MODE_FILTER_ENABLE (1 << 2) +#define MAG_MAPFILTER_NEAREST (0 << 3) +#define MAG_MAPFILTER_LINEAR (1 << 3) +#define MAG_MAPFILTER_ANISOTROPIC (2 << 3) +#define MIN_MAPFILTER_NEAREST (0) +#define MIN_MAPFILTER_LINEAR (1) +#define MIN_MAPFILTER_ANISOTROPIC (2) +#define ENABLE_KEYS (1<<15) +#define DISABLE_COLOR_KEY 0 +#define DISABLE_CHROMA_KEY 0 +#define DISABLE_KILL_PIXEL 0 +#define ENABLE_MIP_MODE_FILTER (1 << 9) +#define MIPFILTER_NONE 0 +#define MIPFILTER_NEAREST 1 +#define MIPFILTER_LINEAR 3 + +#endif diff --git a/lib/i915_3d.h b/lib/i915_3d.h new file mode 100644 index 00000000..04531f33 --- /dev/null +++ b/lib/i915_3d.h @@ -0,0 +1,619 @@ +/* -*- c-basic-offset: 4 -*- */ +/* + * Copyright © 2006,2010 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/* Each instruction is 3 dwords long, though most don't require all + * this space. Maximum of 123 instructions. Smaller maxes per insn + * type. + */ +#define _3DSTATE_PIXEL_SHADER_PROGRAM (CMD_3D|(0x1d<<24)|(0x5<<16)) + +#define REG_TYPE_R 0 /* temporary regs, no need to + * dcl, must be written before + * read -- Preserved between + * phases. + */ +#define REG_TYPE_T 1 /* Interpolated values, must be + * dcl'ed before use. + * + * 0..7: texture coord, + * 8: diffuse spec, + * 9: specular color, + * 10: fog parameter in w. + */ +#define REG_TYPE_CONST 2 /* Restriction: only one const + * can be referenced per + * instruction, though it may be + * selected for multiple inputs. + * Constants not initialized + * default to zero. + */ +#define REG_TYPE_S 3 /* sampler */ +#define REG_TYPE_OC 4 /* output color (rgba) */ +#define REG_TYPE_OD 5 /* output depth (w), xyz are + * temporaries. If not written, + * interpolated depth is used? + */ +#define REG_TYPE_U 6 /* unpreserved temporaries */ +#define REG_TYPE_MASK 0x7 +#define REG_TYPE_SHIFT 4 +#define REG_NR_MASK 0xf + +/* REG_TYPE_T: +*/ +#define T_TEX0 0 +#define T_TEX1 1 +#define T_TEX2 2 +#define T_TEX3 3 +#define T_TEX4 4 +#define T_TEX5 5 +#define T_TEX6 6 +#define T_TEX7 7 +#define T_DIFFUSE 8 +#define T_SPECULAR 9 +#define T_FOG_W 10 /* interpolated fog is in W coord */ + +/* Arithmetic instructions */ + +/* .replicate_swizzle == selection and replication of a particular + * scalar channel, ie., .xxxx, .yyyy, .zzzz or .wwww + */ +#define A0_NOP (0x0<<24) /* no operation */ +#define A0_ADD (0x1<<24) /* dst = src0 + src1 */ +#define A0_MOV (0x2<<24) /* dst = src0 */ +#define A0_MUL (0x3<<24) /* dst = src0 * src1 */ +#define A0_MAD (0x4<<24) /* dst = src0 * src1 + src2 */ +#define A0_DP2ADD (0x5<<24) /* dst.xyzw = src0.xy dot src1.xy + src2.replicate_swizzle */ +#define A0_DP3 (0x6<<24) /* dst.xyzw = src0.xyz dot src1.xyz */ +#define A0_DP4 (0x7<<24) /* dst.xyzw = src0.xyzw dot src1.xyzw */ +#define A0_FRC (0x8<<24) /* dst = src0 - floor(src0) */ +#define A0_RCP (0x9<<24) /* dst.xyzw = 1/(src0.replicate_swizzle) */ +#define A0_RSQ (0xa<<24) /* dst.xyzw = 1/(sqrt(abs(src0.replicate_swizzle))) */ +#define A0_EXP (0xb<<24) /* dst.xyzw = exp2(src0.replicate_swizzle) */ +#define A0_LOG (0xc<<24) /* dst.xyzw = log2(abs(src0.replicate_swizzle)) */ +#define A0_CMP (0xd<<24) /* dst = (src0 >= 0.0) ? src1 : src2 */ +#define A0_MIN (0xe<<24) /* dst = (src0 < src1) ? src0 : src1 */ +#define A0_MAX (0xf<<24) /* dst = (src0 >= src1) ? src0 : src1 */ +#define A0_FLR (0x10<<24) /* dst = floor(src0) */ +#define A0_MOD (0x11<<24) /* dst = src0 fmod 1.0 */ +#define A0_TRC (0x12<<24) /* dst = int(src0) */ +#define A0_SGE (0x13<<24) /* dst = src0 >= src1 ? 1.0 : 0.0 */ +#define A0_SLT (0x14<<24) /* dst = src0 < src1 ? 1.0 : 0.0 */ +#define A0_DEST_SATURATE (1<<22) +#define A0_DEST_TYPE_SHIFT 19 +/* Allow: R, OC, OD, U */ +#define A0_DEST_NR_SHIFT 14 +/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */ +#define A0_DEST_CHANNEL_X (1<<10) +#define A0_DEST_CHANNEL_Y (2<<10) +#define A0_DEST_CHANNEL_Z (4<<10) +#define A0_DEST_CHANNEL_W (8<<10) +#define A0_DEST_CHANNEL_ALL (0xf<<10) +#define A0_DEST_CHANNEL_SHIFT 10 +#define A0_SRC0_TYPE_SHIFT 7 +#define A0_SRC0_NR_SHIFT 2 + +#define A0_DEST_CHANNEL_XY (A0_DEST_CHANNEL_X|A0_DEST_CHANNEL_Y) +#define A0_DEST_CHANNEL_XYZ (A0_DEST_CHANNEL_XY|A0_DEST_CHANNEL_Z) + +#define SRC_X 0 +#define SRC_Y 1 +#define SRC_Z 2 +#define SRC_W 3 +#define SRC_ZERO 4 +#define SRC_ONE 5 + +#define A1_SRC0_CHANNEL_X_NEGATE (1<<31) +#define A1_SRC0_CHANNEL_X_SHIFT 28 +#define A1_SRC0_CHANNEL_Y_NEGATE (1<<27) +#define A1_SRC0_CHANNEL_Y_SHIFT 24 +#define A1_SRC0_CHANNEL_Z_NEGATE (1<<23) +#define A1_SRC0_CHANNEL_Z_SHIFT 20 +#define A1_SRC0_CHANNEL_W_NEGATE (1<<19) +#define A1_SRC0_CHANNEL_W_SHIFT 16 +#define A1_SRC1_TYPE_SHIFT 13 +#define A1_SRC1_NR_SHIFT 8 +#define A1_SRC1_CHANNEL_X_NEGATE (1<<7) +#define A1_SRC1_CHANNEL_X_SHIFT 4 +#define A1_SRC1_CHANNEL_Y_NEGATE (1<<3) +#define A1_SRC1_CHANNEL_Y_SHIFT 0 + +#define A2_SRC1_CHANNEL_Z_NEGATE (1<<31) +#define A2_SRC1_CHANNEL_Z_SHIFT 28 +#define A2_SRC1_CHANNEL_W_NEGATE (1<<27) +#define A2_SRC1_CHANNEL_W_SHIFT 24 +#define A2_SRC2_TYPE_SHIFT 21 +#define A2_SRC2_NR_SHIFT 16 +#define A2_SRC2_CHANNEL_X_NEGATE (1<<15) +#define A2_SRC2_CHANNEL_X_SHIFT 12 +#define A2_SRC2_CHANNEL_Y_NEGATE (1<<11) +#define A2_SRC2_CHANNEL_Y_SHIFT 8 +#define A2_SRC2_CHANNEL_Z_NEGATE (1<<7) +#define A2_SRC2_CHANNEL_Z_SHIFT 4 +#define A2_SRC2_CHANNEL_W_NEGATE (1<<3) +#define A2_SRC2_CHANNEL_W_SHIFT 0 + +/* Texture instructions */ +#define T0_TEXLD (0x15<<24) /* Sample texture using predeclared + * sampler and address, and output + * filtered texel data to destination + * register */ +#define T0_TEXLDP (0x16<<24) /* Same as texld but performs a + * perspective divide of the texture + * coordinate .xyz values by .w before + * sampling. */ +#define T0_TEXLDB (0x17<<24) /* Same as texld but biases the + * computed LOD by w. Only S4.6 two's + * comp is used. This implies that a + * float to fixed conversion is + * done. */ +#define T0_TEXKILL (0x18<<24) /* Does not perform a sampling + * operation. Simply kills the pixel + * if any channel of the address + * register is < 0.0. */ +#define T0_DEST_TYPE_SHIFT 19 +/* Allow: R, OC, OD, U */ +/* Note: U (unpreserved) regs do not retain their values between + * phases (cannot be used for feedback) + * + * Note: oC and OD registers can only be used as the destination of a + * texture instruction once per phase (this is an implementation + * restriction). + */ +#define T0_DEST_NR_SHIFT 14 +/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */ +#define T0_SAMPLER_NR_SHIFT 0 /* This field ignored for TEXKILL */ +#define T0_SAMPLER_NR_MASK (0xf<<0) + +#define T1_ADDRESS_REG_TYPE_SHIFT 24 /* Reg to use as texture coord */ +/* Allow R, T, OC, OD -- R, OC, OD are 'dependent' reads, new program phase */ +#define T1_ADDRESS_REG_NR_SHIFT 17 +#define T2_MBZ 0 + +/* Declaration instructions */ +#define D0_DCL (0x19<<24) /* Declare a t (interpolated attrib) + * register or an s (sampler) + * register. */ +#define D0_SAMPLE_TYPE_SHIFT 22 +#define D0_SAMPLE_TYPE_2D (0x0<<22) +#define D0_SAMPLE_TYPE_CUBE (0x1<<22) +#define D0_SAMPLE_TYPE_VOLUME (0x2<<22) +#define D0_SAMPLE_TYPE_MASK (0x3<<22) + +#define D0_TYPE_SHIFT 19 +/* Allow: T, S */ +#define D0_NR_SHIFT 14 +/* Allow T: 0..10, S: 0..15 */ +#define D0_CHANNEL_X (1<<10) +#define D0_CHANNEL_Y (2<<10) +#define D0_CHANNEL_Z (4<<10) +#define D0_CHANNEL_W (8<<10) +#define D0_CHANNEL_ALL (0xf<<10) +#define D0_CHANNEL_NONE (0<<10) + +#define D0_CHANNEL_XY (D0_CHANNEL_X|D0_CHANNEL_Y) +#define D0_CHANNEL_XYZ (D0_CHANNEL_XY|D0_CHANNEL_Z) + +/* I915 Errata: Do not allow (xz), (xw), (xzw) combinations for diffuse + * or specular declarations. + * + * For T dcls, only allow: (x), (xy), (xyz), (w), (xyzw) + * + * Must be zero for S (sampler) dcls + */ +#define D1_MBZ 0 +#define D2_MBZ 0 + + +/* MASK_* are the unshifted bitmasks of the destination mask in arithmetic + * operations + */ +#define MASK_X 0x1 +#define MASK_Y 0x2 +#define MASK_Z 0x4 +#define MASK_W 0x8 +#define MASK_XYZ (MASK_X | MASK_Y | MASK_Z) +#define MASK_XYZW (MASK_XYZ | MASK_W) +#define MASK_SATURATE 0x10 + +/* Temporary, undeclared regs. Preserved between phases */ +#define FS_R0 ((REG_TYPE_R << REG_TYPE_SHIFT) | 0) +#define FS_R1 ((REG_TYPE_R << REG_TYPE_SHIFT) | 1) +#define FS_R2 ((REG_TYPE_R << REG_TYPE_SHIFT) | 2) +#define FS_R3 ((REG_TYPE_R << REG_TYPE_SHIFT) | 3) + +/* Texture coordinate regs. Must be declared. */ +#define FS_T0 ((REG_TYPE_T << REG_TYPE_SHIFT) | 0) +#define FS_T1 ((REG_TYPE_T << REG_TYPE_SHIFT) | 1) +#define FS_T2 ((REG_TYPE_T << REG_TYPE_SHIFT) | 2) +#define FS_T3 ((REG_TYPE_T << REG_TYPE_SHIFT) | 3) +#define FS_T4 ((REG_TYPE_T << REG_TYPE_SHIFT) | 4) +#define FS_T5 ((REG_TYPE_T << REG_TYPE_SHIFT) | 5) +#define FS_T6 ((REG_TYPE_T << REG_TYPE_SHIFT) | 6) +#define FS_T7 ((REG_TYPE_T << REG_TYPE_SHIFT) | 7) +#define FS_T8 ((REG_TYPE_T << REG_TYPE_SHIFT) | 8) +#define FS_T9 ((REG_TYPE_T << REG_TYPE_SHIFT) | 9) +#define FS_T10 ((REG_TYPE_T << REG_TYPE_SHIFT) | 10) + +/* Constant values */ +#define FS_C0 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 0) +#define FS_C1 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 1) +#define FS_C2 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 2) +#define FS_C3 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 3) +#define FS_C4 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 4) +#define FS_C5 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 5) +#define FS_C6 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 6) +#define FS_C7 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 7) + +/* Sampler regs */ +#define FS_S0 ((REG_TYPE_S << REG_TYPE_SHIFT) | 0) +#define FS_S1 ((REG_TYPE_S << REG_TYPE_SHIFT) | 1) +#define FS_S2 ((REG_TYPE_S << REG_TYPE_SHIFT) | 2) +#define FS_S3 ((REG_TYPE_S << REG_TYPE_SHIFT) | 3) + +/* Output color */ +#define FS_OC ((REG_TYPE_OC << REG_TYPE_SHIFT) | 0) + +/* Output depth */ +#define FS_OD ((REG_TYPE_OD << REG_TYPE_SHIFT) | 0) + +/* Unpreserved temporary regs */ +#define FS_U0 ((REG_TYPE_U << REG_TYPE_SHIFT) | 0) +#define FS_U1 ((REG_TYPE_U << REG_TYPE_SHIFT) | 1) +#define FS_U2 ((REG_TYPE_U << REG_TYPE_SHIFT) | 2) +#define FS_U3 ((REG_TYPE_U << REG_TYPE_SHIFT) | 3) + +#define X_CHANNEL_SHIFT (REG_TYPE_SHIFT + 3) +#define Y_CHANNEL_SHIFT (X_CHANNEL_SHIFT + 4) +#define Z_CHANNEL_SHIFT (Y_CHANNEL_SHIFT + 4) +#define W_CHANNEL_SHIFT (Z_CHANNEL_SHIFT + 4) + +#define REG_CHANNEL_MASK 0xf + +#define REG_NR(reg) ((reg) & REG_NR_MASK) +#define REG_TYPE(reg) (((reg) >> REG_TYPE_SHIFT) & REG_TYPE_MASK) +#define REG_X(reg) (((reg) >> X_CHANNEL_SHIFT) & REG_CHANNEL_MASK) +#define REG_Y(reg) (((reg) >> Y_CHANNEL_SHIFT) & REG_CHANNEL_MASK) +#define REG_Z(reg) (((reg) >> Z_CHANNEL_SHIFT) & REG_CHANNEL_MASK) +#define REG_W(reg) (((reg) >> W_CHANNEL_SHIFT) & REG_CHANNEL_MASK) + +enum i915_fs_channel { + X_CHANNEL_VAL = 0, + Y_CHANNEL_VAL, + Z_CHANNEL_VAL, + W_CHANNEL_VAL, + ZERO_CHANNEL_VAL, + ONE_CHANNEL_VAL, + + NEG_X_CHANNEL_VAL = X_CHANNEL_VAL | 0x8, + NEG_Y_CHANNEL_VAL = Y_CHANNEL_VAL | 0x8, + NEG_Z_CHANNEL_VAL = Z_CHANNEL_VAL | 0x8, + NEG_W_CHANNEL_VAL = W_CHANNEL_VAL | 0x8, + NEG_ONE_CHANNEL_VAL = ONE_CHANNEL_VAL | 0x8 +}; + +#define i915_fs_operand(reg, x, y, z, w) \ + (reg) | \ +(x##_CHANNEL_VAL << X_CHANNEL_SHIFT) | \ +(y##_CHANNEL_VAL << Y_CHANNEL_SHIFT) | \ +(z##_CHANNEL_VAL << Z_CHANNEL_SHIFT) | \ +(w##_CHANNEL_VAL << W_CHANNEL_SHIFT) + +/** + * Construct an operand description for using a register with no swizzling + */ +#define i915_fs_operand_reg(reg) \ + i915_fs_operand(reg, X, Y, Z, W) + +#define i915_fs_operand_reg_negate(reg) \ + i915_fs_operand(reg, NEG_X, NEG_Y, NEG_Z, NEG_W) + +/** + * Returns an operand containing (0.0, 0.0, 0.0, 0.0). + */ +#define i915_fs_operand_zero() i915_fs_operand(FS_R0, ZERO, ZERO, ZERO, ZERO) + +/** + * Returns an unused operand + */ +#define i915_fs_operand_none() i915_fs_operand_zero() + +/** + * Returns an operand containing (1.0, 1.0, 1.0, 1.0). + */ +#define i915_fs_operand_one() i915_fs_operand(FS_R0, ONE, ONE, ONE, ONE) + +#define i915_get_hardware_channel_val(val, shift, negate) \ + (((val & 0x7) << shift) | ((val & 0x8) ? negate : 0)) + +/** + * Outputs a fragment shader command to declare a sampler or texture register. + */ +#define i915_fs_dcl(reg) \ + do { \ + OUT_BATCH(D0_DCL | \ + (REG_TYPE(reg) << D0_TYPE_SHIFT) | \ + (REG_NR(reg) << D0_NR_SHIFT) | \ + ((REG_TYPE(reg) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); \ + OUT_BATCH(0); \ + OUT_BATCH(0); \ + } while (0) + +#define i915_fs_texld(dest_reg, sampler_reg, address_reg) \ + do { \ + OUT_BATCH(T0_TEXLD | \ + (REG_TYPE(dest_reg) << T0_DEST_TYPE_SHIFT) | \ + (REG_NR(dest_reg) << T0_DEST_NR_SHIFT) | \ + (REG_NR(sampler_reg) << T0_SAMPLER_NR_SHIFT)); \ + OUT_BATCH((REG_TYPE(address_reg) << T1_ADDRESS_REG_TYPE_SHIFT) | \ + (REG_NR(address_reg) << T1_ADDRESS_REG_NR_SHIFT)); \ + OUT_BATCH(0); \ + } while (0) + +#define i915_fs_texldp(dest_reg, sampler_reg, address_reg) \ + do { \ + OUT_BATCH(T0_TEXLDP | \ + (REG_TYPE(dest_reg) << T0_DEST_TYPE_SHIFT) | \ + (REG_NR(dest_reg) << T0_DEST_NR_SHIFT) | \ + (REG_NR(sampler_reg) << T0_SAMPLER_NR_SHIFT)); \ + OUT_BATCH((REG_TYPE(address_reg) << T1_ADDRESS_REG_TYPE_SHIFT) | \ + (REG_NR(address_reg) << T1_ADDRESS_REG_NR_SHIFT)); \ + OUT_BATCH(0); \ + } while (0) + +#define i915_fs_arith_masked(op, dest_reg, dest_mask, operand0, operand1, operand2) \ + _i915_fs_arith_masked(A0_##op, dest_reg, dest_mask, operand0, operand1, operand2) + +#define i915_fs_arith(op, dest_reg, operand0, operand1, operand2) \ + _i915_fs_arith(A0_##op, dest_reg, operand0, operand1, operand2) + +#define _i915_fs_arith_masked(cmd, dest_reg, dest_mask, operand0, operand1, operand2) \ + do { \ + /* Set up destination register and write mask */ \ + OUT_BATCH(cmd | \ + (REG_TYPE(dest_reg) << A0_DEST_TYPE_SHIFT) | \ + (REG_NR(dest_reg) << A0_DEST_NR_SHIFT) | \ + (((dest_mask) & ~MASK_SATURATE) << A0_DEST_CHANNEL_SHIFT) | \ + (((dest_mask) & MASK_SATURATE) ? A0_DEST_SATURATE : 0) | \ + /* Set up operand 0 */ \ + (REG_TYPE(operand0) << A0_SRC0_TYPE_SHIFT) | \ + (REG_NR(operand0) << A0_SRC0_NR_SHIFT)); \ + OUT_BATCH(i915_get_hardware_channel_val(REG_X(operand0), \ + A1_SRC0_CHANNEL_X_SHIFT, \ + A1_SRC0_CHANNEL_X_NEGATE) | \ + i915_get_hardware_channel_val(REG_Y(operand0), \ + A1_SRC0_CHANNEL_Y_SHIFT, \ + A1_SRC0_CHANNEL_Y_NEGATE) | \ + i915_get_hardware_channel_val(REG_Z(operand0), \ + A1_SRC0_CHANNEL_Z_SHIFT, \ + A1_SRC0_CHANNEL_Z_NEGATE) | \ + i915_get_hardware_channel_val(REG_W(operand0), \ + A1_SRC0_CHANNEL_W_SHIFT, \ + A1_SRC0_CHANNEL_W_NEGATE) | \ + /* Set up operand 1 */ \ + (REG_TYPE(operand1) << A1_SRC1_TYPE_SHIFT) | \ + (REG_NR(operand1) << A1_SRC1_NR_SHIFT) | \ + i915_get_hardware_channel_val(REG_X(operand1), \ + A1_SRC1_CHANNEL_X_SHIFT, \ + A1_SRC1_CHANNEL_X_NEGATE) | \ + i915_get_hardware_channel_val(REG_Y(operand1), \ + A1_SRC1_CHANNEL_Y_SHIFT, \ + A1_SRC1_CHANNEL_Y_NEGATE)); \ + OUT_BATCH(i915_get_hardware_channel_val(REG_Z(operand1), \ + A2_SRC1_CHANNEL_Z_SHIFT, \ + A2_SRC1_CHANNEL_Z_NEGATE) | \ + i915_get_hardware_channel_val(REG_W(operand1), \ + A2_SRC1_CHANNEL_W_SHIFT, \ + A2_SRC1_CHANNEL_W_NEGATE) | \ + /* Set up operand 2 */ \ + (REG_TYPE(operand2) << A2_SRC2_TYPE_SHIFT) | \ + (REG_NR(operand2) << A2_SRC2_NR_SHIFT) | \ + i915_get_hardware_channel_val(REG_X(operand2), \ + A2_SRC2_CHANNEL_X_SHIFT, \ + A2_SRC2_CHANNEL_X_NEGATE) | \ + i915_get_hardware_channel_val(REG_Y(operand2), \ + A2_SRC2_CHANNEL_Y_SHIFT, \ + A2_SRC2_CHANNEL_Y_NEGATE) | \ + i915_get_hardware_channel_val(REG_Z(operand2), \ + A2_SRC2_CHANNEL_Z_SHIFT, \ + A2_SRC2_CHANNEL_Z_NEGATE) | \ + i915_get_hardware_channel_val(REG_W(operand2), \ + A2_SRC2_CHANNEL_W_SHIFT, \ + A2_SRC2_CHANNEL_W_NEGATE)); \ + } while (0) + +#define _i915_fs_arith(cmd, dest_reg, operand0, operand1, operand2) do {\ + /* Set up destination register and write mask */ \ + OUT_BATCH(cmd | \ + (REG_TYPE(dest_reg) << A0_DEST_TYPE_SHIFT) | \ + (REG_NR(dest_reg) << A0_DEST_NR_SHIFT) | \ + (A0_DEST_CHANNEL_ALL) | \ + /* Set up operand 0 */ \ + (REG_TYPE(operand0) << A0_SRC0_TYPE_SHIFT) | \ + (REG_NR(operand0) << A0_SRC0_NR_SHIFT)); \ + OUT_BATCH(i915_get_hardware_channel_val(REG_X(operand0), \ + A1_SRC0_CHANNEL_X_SHIFT, \ + A1_SRC0_CHANNEL_X_NEGATE) | \ + i915_get_hardware_channel_val(REG_Y(operand0), \ + A1_SRC0_CHANNEL_Y_SHIFT, \ + A1_SRC0_CHANNEL_Y_NEGATE) | \ + i915_get_hardware_channel_val(REG_Z(operand0), \ + A1_SRC0_CHANNEL_Z_SHIFT, \ + A1_SRC0_CHANNEL_Z_NEGATE) | \ + i915_get_hardware_channel_val(REG_W(operand0), \ + A1_SRC0_CHANNEL_W_SHIFT, \ + A1_SRC0_CHANNEL_W_NEGATE) | \ + /* Set up operand 1 */ \ + (REG_TYPE(operand1) << A1_SRC1_TYPE_SHIFT) | \ + (REG_NR(operand1) << A1_SRC1_NR_SHIFT) | \ + i915_get_hardware_channel_val(REG_X(operand1), \ + A1_SRC1_CHANNEL_X_SHIFT, \ + A1_SRC1_CHANNEL_X_NEGATE) | \ + i915_get_hardware_channel_val(REG_Y(operand1), \ + A1_SRC1_CHANNEL_Y_SHIFT, \ + A1_SRC1_CHANNEL_Y_NEGATE)); \ + OUT_BATCH(i915_get_hardware_channel_val(REG_Z(operand1), \ + A2_SRC1_CHANNEL_Z_SHIFT, \ + A2_SRC1_CHANNEL_Z_NEGATE) | \ + i915_get_hardware_channel_val(REG_W(operand1), \ + A2_SRC1_CHANNEL_W_SHIFT, \ + A2_SRC1_CHANNEL_W_NEGATE) | \ + /* Set up operand 2 */ \ + (REG_TYPE(operand2) << A2_SRC2_TYPE_SHIFT) | \ + (REG_NR(operand2) << A2_SRC2_NR_SHIFT) | \ + i915_get_hardware_channel_val(REG_X(operand2), \ + A2_SRC2_CHANNEL_X_SHIFT, \ + A2_SRC2_CHANNEL_X_NEGATE) | \ + i915_get_hardware_channel_val(REG_Y(operand2), \ + A2_SRC2_CHANNEL_Y_SHIFT, \ + A2_SRC2_CHANNEL_Y_NEGATE) | \ + i915_get_hardware_channel_val(REG_Z(operand2), \ + A2_SRC2_CHANNEL_Z_SHIFT, \ + A2_SRC2_CHANNEL_Z_NEGATE) | \ + i915_get_hardware_channel_val(REG_W(operand2), \ + A2_SRC2_CHANNEL_W_SHIFT, \ + A2_SRC2_CHANNEL_W_NEGATE)); \ +} while (0) + +#define i915_fs_mov(dest_reg, operand0) \ + i915_fs_arith(MOV, dest_reg, \ + operand0, \ + i915_fs_operand_none(), \ + i915_fs_operand_none()) + +#define i915_fs_mov_masked(dest_reg, dest_mask, operand0) \ + i915_fs_arith_masked (MOV, dest_reg, dest_mask, \ + operand0, \ + i915_fs_operand_none(), \ + i915_fs_operand_none()) + + +#define i915_fs_frc(dest_reg, operand0) \ + i915_fs_arith (FRC, dest_reg, \ + operand0, \ + i915_fs_operand_none(), \ + i915_fs_operand_none()) + +/** Add operand0 and operand1 and put the result in dest_reg */ +#define i915_fs_add(dest_reg, operand0, operand1) \ + i915_fs_arith (ADD, dest_reg, \ + operand0, operand1, \ + i915_fs_operand_none()) + +/** Multiply operand0 and operand1 and put the result in dest_reg */ +#define i915_fs_mul(dest_reg, operand0, operand1) \ + i915_fs_arith (MUL, dest_reg, \ + operand0, operand1, \ + i915_fs_operand_none()) + +/** Computes 1/sqrt(operand0.replicate_swizzle) puts the result in dest_reg */ +#define i915_fs_rsq(dest_reg, dest_mask, operand0) \ + do { \ + if (dest_mask) { \ + i915_fs_arith_masked (RSQ, dest_reg, dest_mask, \ + operand0, \ + i915_fs_operand_none (), \ + i915_fs_operand_none ()); \ + } else { \ + i915_fs_arith (RSQ, dest_reg, \ + operand0, \ + i915_fs_operand_none (), \ + i915_fs_operand_none ()); \ + } \ + } while (0) + +/** Puts the minimum of operand0 and operand1 in dest_reg */ +#define i915_fs_min(dest_reg, operand0, operand1) \ + i915_fs_arith (MIN, dest_reg, \ + operand0, operand1, \ + i915_fs_operand_none()) + +/** Puts the maximum of operand0 and operand1 in dest_reg */ +#define i915_fs_max(dest_reg, operand0, operand1) \ + i915_fs_arith (MAX, dest_reg, \ + operand0, operand1, \ + i915_fs_operand_none()) + +#define i915_fs_cmp(dest_reg, operand0, operand1, operand2) \ + i915_fs_arith (CMP, dest_reg, operand0, operand1, operand2) + +/** Perform operand0 * operand1 + operand2 and put the result in dest_reg */ +#define i915_fs_mad(dest_reg, dest_mask, op0, op1, op2) \ + do { \ + if (dest_mask) { \ + i915_fs_arith_masked (MAD, dest_reg, dest_mask, op0, op1, op2); \ + } else { \ + i915_fs_arith (MAD, dest_reg, op0, op1, op2); \ + } \ + } while (0) + +#define i915_fs_dp2add(dest_reg, dest_mask, op0, op1, op2) \ + do { \ + if (dest_mask) { \ + i915_fs_arith_masked (DP2ADD, dest_reg, dest_mask, op0, op1, op2); \ + } else { \ + i915_fs_arith (DP2ADD, dest_reg, op0, op1, op2); \ + } \ + } while (0) + +/** + * Perform a 3-component dot-product of operand0 and operand1 and put the + * resulting scalar in the channels of dest_reg specified by the dest_mask. + */ +#define i915_fs_dp3(dest_reg, dest_mask, op0, op1) \ + do { \ + if (dest_mask) { \ + i915_fs_arith_masked (DP3, dest_reg, dest_mask, \ + op0, op1,\ + i915_fs_operand_none()); \ + } else { \ + i915_fs_arith (DP3, dest_reg, op0, op1,\ + i915_fs_operand_none()); \ + } \ + } while (0) + +/** + * Sets up local state for accumulating a fragment shader buffer. + * + * \param x maximum number of shader commands that may be used between + * a FS_START and FS_END + */ +#define FS_LOCALS() \ + uint32_t _shader_offset + +#define FS_BEGIN() \ + do { \ + _shader_offset = intel->batch_used++; \ + } while (0) + +#define FS_END() \ + do { \ + intel->batch_ptr[_shader_offset] = \ + _3DSTATE_PIXEL_SHADER_PROGRAM | \ + (intel->batch_used - _shader_offset - 2); \ + } while (0); diff --git a/lib/i915_reg.h b/lib/i915_reg.h new file mode 100644 index 00000000..746a4131 --- /dev/null +++ b/lib/i915_reg.h @@ -0,0 +1,844 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 _I915_REG_H_ +#define _I915_REG_H_ + +#define I915_SET_FIELD( var, mask, value ) (var &= ~(mask), var |= value) + +#define CMD_3D (0x3<<29) + +#define PRIM3D (CMD_3D | (0x1f<<24)) +#define PRIM3D_INDIRECT_SEQUENTIAL ((1<<23) | (0<<17)) +#define PRIM3D_TRILIST (PRIM3D | (0x0<<18)) +#define PRIM3D_TRISTRIP (PRIM3D | (0x1<<18)) +#define PRIM3D_TRISTRIP_RVRSE (PRIM3D | (0x2<<18)) +#define PRIM3D_TRIFAN (PRIM3D | (0x3<<18)) +#define PRIM3D_POLY (PRIM3D | (0x4<<18)) +#define PRIM3D_LINELIST (PRIM3D | (0x5<<18)) +#define PRIM3D_LINESTRIP (PRIM3D | (0x6<<18)) +#define PRIM3D_RECTLIST (PRIM3D | (0x7<<18)) +#define PRIM3D_POINTLIST (PRIM3D | (0x8<<18)) +#define PRIM3D_DIB (PRIM3D | (0x9<<18)) +#define PRIM3D_CLEAR_RECT (PRIM3D | (0xa<<18)) +#define PRIM3D_ZONE_INIT (PRIM3D | (0xd<<18)) +#define PRIM3D_MASK (0x1f<<18) + +/* p137 */ +#define _3DSTATE_AA_CMD (CMD_3D | (0x06<<24)) +#define AA_LINE_ECAAR_WIDTH_ENABLE (1<<16) +#define AA_LINE_ECAAR_WIDTH_0_5 0 +#define AA_LINE_ECAAR_WIDTH_1_0 (1<<14) +#define AA_LINE_ECAAR_WIDTH_2_0 (2<<14) +#define AA_LINE_ECAAR_WIDTH_4_0 (3<<14) +#define AA_LINE_REGION_WIDTH_ENABLE (1<<8) +#define AA_LINE_REGION_WIDTH_0_5 0 +#define AA_LINE_REGION_WIDTH_1_0 (1<<6) +#define AA_LINE_REGION_WIDTH_2_0 (2<<6) +#define AA_LINE_REGION_WIDTH_4_0 (3<<6) + +/* 3DSTATE_BACKFACE_STENCIL_OPS, p138*/ +#define _3DSTATE_BACKFACE_STENCIL_OPS (CMD_3D | (0x8<<24)) +#define BFO_ENABLE_STENCIL_REF (1<<23) +#define BFO_STENCIL_REF_SHIFT 15 +#define BFO_STENCIL_REF_MASK (0xff<<15) +#define BFO_ENABLE_STENCIL_FUNCS (1<<14) +#define BFO_STENCIL_TEST_SHIFT 11 +#define BFO_STENCIL_TEST_MASK (0x7<<11) +#define BFO_STENCIL_FAIL_SHIFT 8 +#define BFO_STENCIL_FAIL_MASK (0x7<<8) +#define BFO_STENCIL_PASS_Z_FAIL_SHIFT 5 +#define BFO_STENCIL_PASS_Z_FAIL_MASK (0x7<<5) +#define BFO_STENCIL_PASS_Z_PASS_SHIFT 2 +#define BFO_STENCIL_PASS_Z_PASS_MASK (0x7<<2) +#define BFO_ENABLE_STENCIL_TWO_SIDE (1<<1) +#define BFO_STENCIL_TWO_SIDE (1<<0) + +/* 3DSTATE_BACKFACE_STENCIL_MASKS, p140 */ +#define _3DSTATE_BACKFACE_STENCIL_MASKS (CMD_3D | (0x9<<24)) +#define BFM_ENABLE_STENCIL_TEST_MASK (1<<17) +#define BFM_ENABLE_STENCIL_WRITE_MASK (1<<16) +#define BFM_STENCIL_TEST_MASK_SHIFT 8 +#define BFM_STENCIL_TEST_MASK_MASK (0xff<<8) +#define BFM_STENCIL_WRITE_MASK_SHIFT 0 +#define BFM_STENCIL_WRITE_MASK_MASK (0xff<<0) + +/* 3DSTATE_BIN_CONTROL p141 */ + +/* p143 */ +#define _3DSTATE_BUF_INFO_CMD (CMD_3D | (0x1d<<24) | (0x8e<<16) | 1) +/* Dword 1 */ +#define BUF_3D_ID_COLOR_BACK (0x3<<24) +#define BUF_3D_ID_DEPTH (0x7<<24) +#define BUF_3D_USE_FENCE (1<<23) +#define BUF_3D_TILED_SURFACE (1<<22) +#define BUF_3D_TILE_WALK_X 0 +#define BUF_3D_TILE_WALK_Y (1<<21) +#define BUF_3D_PITCH(x) (((x)/4)<<2) +/* Dword 2 */ +#define BUF_3D_ADDR(x) ((x) & ~0x3) + +/* 3DSTATE_CHROMA_KEY */ + +/* 3DSTATE_CLEAR_PARAMETERS, p150 */ +#define _3DSTATE_CLEAR_PARAMETERS (CMD_3D | (0x1d<<24) | (0x9c<<16) | 5) +/* Dword 1 */ +#define CLEARPARAM_CLEAR_RECT (1 << 16) +#define CLEARPARAM_ZONE_INIT (0 << 16) +#define CLEARPARAM_WRITE_COLOR (1 << 2) +#define CLEARPARAM_WRITE_DEPTH (1 << 1) +#define CLEARPARAM_WRITE_STENCIL (1 << 0) + +/* 3DSTATE_CONSTANT_BLEND_COLOR, p153 */ +#define _3DSTATE_CONST_BLEND_COLOR_CMD (CMD_3D | (0x1d<<24) | (0x88<<16)) + +/* 3DSTATE_COORD_SET_BINDINGS, p154 */ +#define _3DSTATE_COORD_SET_BINDINGS (CMD_3D | (0x16<<24)) +#define CSB_TCB(iunit, eunit) ((eunit)<<(iunit*3)) + +/* p156 */ +#define _3DSTATE_DFLT_DIFFUSE_CMD (CMD_3D | (0x1d<<24) | (0x99<<16)) + +/* p157 */ +#define _3DSTATE_DFLT_SPEC_CMD (CMD_3D | (0x1d<<24) | (0x9a<<16)) + +/* p158 */ +#define _3DSTATE_DFLT_Z_CMD (CMD_3D | (0x1d<<24) | (0x98<<16)) + +/* 3DSTATE_DEPTH_OFFSET_SCALE, p159 */ +#define _3DSTATE_DEPTH_OFFSET_SCALE (CMD_3D | (0x1d<<24) | (0x97<<16)) +/* scale in dword 1 */ + +/* The depth subrectangle is not supported, but must be disabled. */ +/* 3DSTATE_DEPTH_SUBRECT_DISABLE, p160 */ +#define _3DSTATE_DEPTH_SUBRECT_DISABLE (CMD_3D | (0x1c<<24) | (0x11<<19) | (1 << 1) | (0 << 0)) + +/* p161 */ +#define _3DSTATE_DST_BUF_VARS_CMD (CMD_3D | (0x1d<<24) | (0x85<<16)) +/* Dword 1 */ +#define TEX_DEFAULT_COLOR_OGL (0<<30) +#define TEX_DEFAULT_COLOR_D3D (1<<30) +#define ZR_EARLY_DEPTH (1<<29) +#define LOD_PRECLAMP_OGL (1<<28) +#define LOD_PRECLAMP_D3D (0<<28) +#define DITHER_FULL_ALWAYS (0<<26) +#define DITHER_FULL_ON_FB_BLEND (1<<26) +#define DITHER_CLAMPED_ALWAYS (2<<26) +#define LINEAR_GAMMA_BLEND_32BPP (1<<25) +#define DEBUG_DISABLE_ENH_DITHER (1<<24) +#define DSTORG_HORT_BIAS(x) ((x)<<20) +#define DSTORG_VERT_BIAS(x) ((x)<<16) +#define COLOR_4_2_2_CHNL_WRT_ALL 0 +#define COLOR_4_2_2_CHNL_WRT_Y (1<<12) +#define COLOR_4_2_2_CHNL_WRT_CR (2<<12) +#define COLOR_4_2_2_CHNL_WRT_CB (3<<12) +#define COLOR_4_2_2_CHNL_WRT_CRCB (4<<12) +#define COLR_BUF_8BIT 0 +#define COLR_BUF_RGB555 (1<<8) +#define COLR_BUF_RGB565 (2<<8) +#define COLR_BUF_ARGB8888 (3<<8) +#define COLR_BUF_ARGB4444 (8<<8) +#define COLR_BUF_ARGB1555 (9<<8) +#define COLR_BUF_ARGB2AAA (0xa<<8) +#define DEPTH_FRMT_16_FIXED 0 +#define DEPTH_FRMT_16_FLOAT (1<<2) +#define DEPTH_FRMT_24_FIXED_8_OTHER (2<<2) +#define VERT_LINE_STRIDE_1 (1<<1) +#define VERT_LINE_STRIDE_0 (0<<1) +#define VERT_LINE_STRIDE_OFS_1 1 +#define VERT_LINE_STRIDE_OFS_0 0 + +/* p166 */ +#define _3DSTATE_DRAW_RECT_CMD (CMD_3D|(0x1d<<24)|(0x80<<16)|3) +/* Dword 1 */ +#define DRAW_RECT_DIS_DEPTH_OFS (1<<30) +#define DRAW_DITHER_OFS_X(x) ((x)<<26) +#define DRAW_DITHER_OFS_Y(x) ((x)<<24) +/* Dword 2 */ +#define DRAW_YMIN(x) ((x)<<16) +#define DRAW_XMIN(x) (x) +/* Dword 3 */ +#define DRAW_YMAX(x) ((x)<<16) +#define DRAW_XMAX(x) (x) +/* Dword 4 */ +#define DRAW_YORG(x) ((x)<<16) +#define DRAW_XORG(x) (x) + +/* 3DSTATE_FILTER_COEFFICIENTS_4X4, p170 */ + +/* 3DSTATE_FILTER_COEFFICIENTS_6X5, p172 */ + +/* _3DSTATE_FOG_COLOR, p173 */ +#define _3DSTATE_FOG_COLOR_CMD (CMD_3D|(0x15<<24)) +#define FOG_COLOR_RED(x) ((x)<<16) +#define FOG_COLOR_GREEN(x) ((x)<<8) +#define FOG_COLOR_BLUE(x) (x) + +/* _3DSTATE_FOG_MODE, p174 */ +#define _3DSTATE_FOG_MODE_CMD (CMD_3D|(0x1d<<24)|(0x89<<16)|2) +/* Dword 1 */ +#define FMC1_FOGFUNC_MODIFY_ENABLE (1<<31) +#define FMC1_FOGFUNC_VERTEX (0<<28) +#define FMC1_FOGFUNC_PIXEL_EXP (1<<28) +#define FMC1_FOGFUNC_PIXEL_EXP2 (2<<28) +#define FMC1_FOGFUNC_PIXEL_LINEAR (3<<28) +#define FMC1_FOGFUNC_MASK (3<<28) +#define FMC1_FOGINDEX_MODIFY_ENABLE (1<<27) +#define FMC1_FOGINDEX_Z (0<<25) +#define FMC1_FOGINDEX_W (1<<25) +#define FMC1_C1_C2_MODIFY_ENABLE (1<<24) +#define FMC1_DENSITY_MODIFY_ENABLE (1<<23) +#define FMC1_C1_ONE (1<<13) +#define FMC1_C1_MASK (0xffff<<4) +/* Dword 2 */ +#define FMC2_C2_ONE (1<<16) +/* Dword 3 */ +#define FMC3_D_ONE (1<<16) + +/* _3DSTATE_INDEPENDENT_ALPHA_BLEND, p177 */ +#define _3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD (CMD_3D|(0x0b<<24)) +#define IAB_MODIFY_ENABLE (1<<23) +#define IAB_ENABLE (1<<22) +#define IAB_MODIFY_FUNC (1<<21) +#define IAB_FUNC_SHIFT 16 +#define IAB_MODIFY_SRC_FACTOR (1<<11) +#define IAB_SRC_FACTOR_SHIFT 6 +#define IAB_SRC_FACTOR_MASK (BLENDFACT_MASK<<6) +#define IAB_MODIFY_DST_FACTOR (1<<5) +#define IAB_DST_FACTOR_SHIFT 0 +#define IAB_DST_FACTOR_MASK (BLENDFACT_MASK<<0) + +#define BLENDFACT_ZERO 0x01 +#define BLENDFACT_ONE 0x02 +#define BLENDFACT_SRC_COLR 0x03 +#define BLENDFACT_INV_SRC_COLR 0x04 +#define BLENDFACT_SRC_ALPHA 0x05 +#define BLENDFACT_INV_SRC_ALPHA 0x06 +#define BLENDFACT_DST_ALPHA 0x07 +#define BLENDFACT_INV_DST_ALPHA 0x08 +#define BLENDFACT_DST_COLR 0x09 +#define BLENDFACT_INV_DST_COLR 0x0a +#define BLENDFACT_SRC_ALPHA_SATURATE 0x0b +#define BLENDFACT_CONST_COLOR 0x0c +#define BLENDFACT_INV_CONST_COLOR 0x0d +#define BLENDFACT_CONST_ALPHA 0x0e +#define BLENDFACT_INV_CONST_ALPHA 0x0f +#define BLENDFACT_MASK 0x0f + +#define BLENDFUNC_ADD 0x0 +#define BLENDFUNC_SUBTRACT 0x1 +#define BLENDFUNC_REVERSE_SUBTRACT 0x2 +#define BLENDFUNC_MIN 0x3 +#define BLENDFUNC_MAX 0x4 +#define BLENDFUNC_MASK 0x7 + +/* 3DSTATE_LOAD_INDIRECT, p180 */ + +#define _3DSTATE_LOAD_INDIRECT (CMD_3D|(0x1d<<24)|(0x7<<16)) +#define LI0_STATE_STATIC_INDIRECT (0x01<<8) +#define LI0_STATE_DYNAMIC_INDIRECT (0x02<<8) +#define LI0_STATE_SAMPLER (0x04<<8) +#define LI0_STATE_MAP (0x08<<8) +#define LI0_STATE_PROGRAM (0x10<<8) +#define LI0_STATE_CONSTANTS (0x20<<8) + +#define SIS0_BUFFER_ADDRESS(x) ((x)&~0x3) +#define SIS0_FORCE_LOAD (1<<1) +#define SIS0_BUFFER_VALID (1<<0) +#define SIS1_BUFFER_LENGTH(x) ((x)&0xff) + +#define DIS0_BUFFER_ADDRESS(x) ((x)&~0x3) +#define DIS0_BUFFER_RESET (1<<1) +#define DIS0_BUFFER_VALID (1<<0) + +#define SSB0_BUFFER_ADDRESS(x) ((x)&~0x3) +#define SSB0_FORCE_LOAD (1<<1) +#define SSB0_BUFFER_VALID (1<<0) +#define SSB1_BUFFER_LENGTH(x) ((x)&0xff) + +#define MSB0_BUFFER_ADDRESS(x) ((x)&~0x3) +#define MSB0_FORCE_LOAD (1<<1) +#define MSB0_BUFFER_VALID (1<<0) +#define MSB1_BUFFER_LENGTH(x) ((x)&0xff) + +#define PSP0_BUFFER_ADDRESS(x) ((x)&~0x3) +#define PSP0_FORCE_LOAD (1<<1) +#define PSP0_BUFFER_VALID (1<<0) +#define PSP1_BUFFER_LENGTH(x) ((x)&0xff) + +#define PSC0_BUFFER_ADDRESS(x) ((x)&~0x3) +#define PSC0_FORCE_LOAD (1<<1) +#define PSC0_BUFFER_VALID (1<<0) +#define PSC1_BUFFER_LENGTH(x) ((x)&0xff) + +/* _3DSTATE_RASTERIZATION_RULES */ +#define _3DSTATE_RASTER_RULES_CMD (CMD_3D|(0x07<<24)) +#define ENABLE_POINT_RASTER_RULE (1<<15) +#define OGL_POINT_RASTER_RULE (1<<13) +#define ENABLE_TEXKILL_3D_4D (1<<10) +#define TEXKILL_3D (0<<9) +#define TEXKILL_4D (1<<9) +#define ENABLE_LINE_STRIP_PROVOKE_VRTX (1<<8) +#define ENABLE_TRI_FAN_PROVOKE_VRTX (1<<5) +#define LINE_STRIP_PROVOKE_VRTX(x) ((x)<<6) +#define TRI_FAN_PROVOKE_VRTX(x) ((x)<<3) + +/* _3DSTATE_SCISSOR_ENABLE, p256 */ +#define _3DSTATE_SCISSOR_ENABLE_CMD (CMD_3D|(0x1c<<24)|(0x10<<19)) +#define ENABLE_SCISSOR_RECT ((1<<1) | 1) +#define DISABLE_SCISSOR_RECT (1<<1) + +/* _3DSTATE_SCISSOR_RECTANGLE_0, p257 */ +#define _3DSTATE_SCISSOR_RECT_0_CMD (CMD_3D|(0x1d<<24)|(0x81<<16)|1) +/* Dword 1 */ +#define SCISSOR_RECT_0_YMIN(x) ((x)<<16) +#define SCISSOR_RECT_0_XMIN(x) (x) +/* Dword 2 */ +#define SCISSOR_RECT_0_YMAX(x) ((x)<<16) +#define SCISSOR_RECT_0_XMAX(x) (x) + +/* p189 */ +#define _3DSTATE_LOAD_STATE_IMMEDIATE_1 ((0x3<<29)|(0x1d<<24)|(0x04<<16)) +#define I1_LOAD_S(n) (1<<(4+n)) + +#define S0_VB_OFFSET_MASK 0xffffffc +#define S0_AUTO_CACHE_INV_DISABLE (1<<0) + +#define S1_VERTEX_WIDTH_SHIFT 24 +#define S1_VERTEX_WIDTH_MASK (0x3f<<24) +#define S1_VERTEX_PITCH_SHIFT 16 +#define S1_VERTEX_PITCH_MASK (0x3f<<16) + +#define TEXCOORDFMT_2D 0x0 +#define TEXCOORDFMT_3D 0x1 +#define TEXCOORDFMT_4D 0x2 +#define TEXCOORDFMT_1D 0x3 +#define TEXCOORDFMT_2D_16 0x4 +#define TEXCOORDFMT_4D_16 0x5 +#define TEXCOORDFMT_NOT_PRESENT 0xf +#define S2_TEXCOORD_FMT0_MASK 0xf +#define S2_TEXCOORD_FMT1_SHIFT 4 +#define S2_TEXCOORD_FMT(unit, type) ((type)<<(unit*4)) +#define S2_TEXCOORD_NONE (~0) + +#define TEXCOORD_WRAP_SHORTEST_TCX 8 +#define TEXCOORD_WRAP_SHORTEST_TCY 4 +#define TEXCOORD_WRAP_SHORTEST_TCZ 2 +#define TEXCOORD_PERSPECTIVE_DISABLE 1 + +#define S3_WRAP_SHORTEST_TCX(unit) (TEXCOORD_WRAP_SHORTEST_TCX << ((unit) * 4)) +#define S3_WRAP_SHORTEST_TCY(unit) (TEXCOORD_WRAP_SHORTEST_TCY << ((unit) * 4)) +#define S3_WRAP_SHORTEST_TCZ(unit) (TEXCOORD_WRAP_SHORTEST_TCZ << ((unit) * 4)) +#define S3_PERSPECTIVE_DISABLE(unit) (TEXCOORD_PERSPECTIVE_DISABLE << ((unit) * 4)) + +/* S3 not interesting */ + +#define S4_POINT_WIDTH_SHIFT 23 +#define S4_POINT_WIDTH_MASK (0x1ff<<23) +#define S4_LINE_WIDTH_SHIFT 19 +#define S4_LINE_WIDTH_ONE (0x2<<19) +#define S4_LINE_WIDTH_MASK (0xf<<19) +#define S4_FLATSHADE_ALPHA (1<<18) +#define S4_FLATSHADE_FOG (1<<17) +#define S4_FLATSHADE_SPECULAR (1<<16) +#define S4_FLATSHADE_COLOR (1<<15) +#define S4_CULLMODE_BOTH (0<<13) +#define S4_CULLMODE_NONE (1<<13) +#define S4_CULLMODE_CW (2<<13) +#define S4_CULLMODE_CCW (3<<13) +#define S4_CULLMODE_MASK (3<<13) +#define S4_VFMT_POINT_WIDTH (1<<12) +#define S4_VFMT_SPEC_FOG (1<<11) +#define S4_VFMT_COLOR (1<<10) +#define S4_VFMT_DEPTH_OFFSET (1<<9) +#define S4_VFMT_XYZ (1<<6) +#define S4_VFMT_XYZW (2<<6) +#define S4_VFMT_XY (3<<6) +#define S4_VFMT_XYW (4<<6) +#define S4_VFMT_XYZW_MASK (7<<6) +#define S4_FORCE_DEFAULT_DIFFUSE (1<<5) +#define S4_FORCE_DEFAULT_SPECULAR (1<<4) +#define S4_LOCAL_DEPTH_OFFSET_ENABLE (1<<3) +#define S4_VFMT_FOG_PARAM (1<<2) +#define S4_SPRITE_POINT_ENABLE (1<<1) +#define S4_LINE_ANTIALIAS_ENABLE (1<<0) + +#define S4_VFMT_MASK (S4_VFMT_POINT_WIDTH | \ + S4_VFMT_SPEC_FOG | \ + S4_VFMT_COLOR | \ + S4_VFMT_DEPTH_OFFSET | \ + S4_VFMT_XYZW_MASK | \ + S4_VFMT_FOG_PARAM) + +#define S5_WRITEDISABLE_ALPHA (1<<31) +#define S5_WRITEDISABLE_RED (1<<30) +#define S5_WRITEDISABLE_GREEN (1<<29) +#define S5_WRITEDISABLE_BLUE (1<<28) +#define S5_WRITEDISABLE_MASK (0xf<<28) +#define S5_FORCE_DEFAULT_POINT_SIZE (1<<27) +#define S5_LAST_PIXEL_ENABLE (1<<26) +#define S5_GLOBAL_DEPTH_OFFSET_ENABLE (1<<25) +#define S5_FOG_ENABLE (1<<24) +#define S5_STENCIL_REF_SHIFT 16 +#define S5_STENCIL_REF_MASK (0xff<<16) +#define S5_STENCIL_TEST_FUNC_SHIFT 13 +#define S5_STENCIL_TEST_FUNC_MASK (0x7<<13) +#define S5_STENCIL_FAIL_SHIFT 10 +#define S5_STENCIL_FAIL_MASK (0x7<<10) +#define S5_STENCIL_PASS_Z_FAIL_SHIFT 7 +#define S5_STENCIL_PASS_Z_FAIL_MASK (0x7<<7) +#define S5_STENCIL_PASS_Z_PASS_SHIFT 4 +#define S5_STENCIL_PASS_Z_PASS_MASK (0x7<<4) +#define S5_STENCIL_WRITE_ENABLE (1<<3) +#define S5_STENCIL_TEST_ENABLE (1<<2) +#define S5_COLOR_DITHER_ENABLE (1<<1) +#define S5_LOGICOP_ENABLE (1<<0) + +#define S6_ALPHA_TEST_ENABLE (1<<31) +#define S6_ALPHA_TEST_FUNC_SHIFT 28 +#define S6_ALPHA_TEST_FUNC_MASK (0x7<<28) +#define S6_ALPHA_REF_SHIFT 20 +#define S6_ALPHA_REF_MASK (0xff<<20) +#define S6_DEPTH_TEST_ENABLE (1<<19) +#define S6_DEPTH_TEST_FUNC_SHIFT 16 +#define S6_DEPTH_TEST_FUNC_MASK (0x7<<16) +#define S6_CBUF_BLEND_ENABLE (1<<15) +#define S6_CBUF_BLEND_FUNC_SHIFT 12 +#define S6_CBUF_BLEND_FUNC_MASK (0x7<<12) +#define S6_CBUF_SRC_BLEND_FACT_SHIFT 8 +#define S6_CBUF_SRC_BLEND_FACT_MASK (0xf<<8) +#define S6_CBUF_DST_BLEND_FACT_SHIFT 4 +#define S6_CBUF_DST_BLEND_FACT_MASK (0xf<<4) +#define S6_DEPTH_WRITE_ENABLE (1<<3) +#define S6_COLOR_WRITE_ENABLE (1<<2) +#define S6_TRISTRIP_PV_SHIFT 0 +#define S6_TRISTRIP_PV_MASK (0x3<<0) + +#define S7_DEPTH_OFFSET_CONST_MASK ~0 + +/* 3DSTATE_MAP_DEINTERLACER_PARAMETERS */ +/* 3DSTATE_MAP_PALETTE_LOAD_32, p206 */ + +/* _3DSTATE_MODES_4, p218 */ +#define _3DSTATE_MODES_4_CMD (CMD_3D|(0x0d<<24)) +#define ENABLE_LOGIC_OP_FUNC (1<<23) +#define LOGIC_OP_FUNC(x) ((x)<<18) +#define LOGICOP_MASK (0xf<<18) +#define LOGICOP_COPY 0xc +#define MODE4_ENABLE_STENCIL_TEST_MASK ((1<<17)|(0xff00)) +#define ENABLE_STENCIL_TEST_MASK (1<<17) +#define STENCIL_TEST_MASK(x) ((x)<<8) +#define MODE4_ENABLE_STENCIL_WRITE_MASK ((1<<16)|(0x00ff)) +#define ENABLE_STENCIL_WRITE_MASK (1<<16) +#define STENCIL_WRITE_MASK(x) ((x)&0xff) + +/* _3DSTATE_MODES_5, p220 */ +#define _3DSTATE_MODES_5_CMD (CMD_3D|(0x0c<<24)) +#define PIPELINE_FLUSH_RENDER_CACHE (1<<18) +#define PIPELINE_FLUSH_TEXTURE_CACHE (1<<16) + +/* p221 */ +#define _3DSTATE_PIXEL_SHADER_CONSTANTS (CMD_3D|(0x1d<<24)|(0x6<<16)) +#define PS1_REG(n) (1<<(n)) +#define PS2_CONST_X(n) (n) +#define PS3_CONST_Y(n) (n) +#define PS4_CONST_Z(n) (n) +#define PS5_CONST_W(n) (n) + +/* p222 */ + +#define I915_MAX_TEX_INDIRECT 4 +#define I915_MAX_TEX_INSN 32 +#define I915_MAX_ALU_INSN 64 +#define I915_MAX_DECL_INSN 27 +#define I915_MAX_TEMPORARY 16 + +/* Each instruction is 3 dwords long, though most don't require all + * this space. Maximum of 123 instructions. Smaller maxes per insn + * type. + */ +#define _3DSTATE_PIXEL_SHADER_PROGRAM (CMD_3D|(0x1d<<24)|(0x5<<16)) + +#define REG_TYPE_R 0 /* temporary regs, no need to + * dcl, must be written before + * read -- Preserved between + * phases. + */ +#define REG_TYPE_T 1 /* Interpolated values, must be + * dcl'ed before use. + * + * 0..7: texture coord, + * 8: diffuse spec, + * 9: specular color, + * 10: fog parameter in w. + */ +#define REG_TYPE_CONST 2 /* Restriction: only one const + * can be referenced per + * instruction, though it may be + * selected for multiple inputs. + * Constants not initialized + * default to zero. + */ +#define REG_TYPE_S 3 /* sampler */ +#define REG_TYPE_OC 4 /* output color (rgba) */ +#define REG_TYPE_OD 5 /* output depth (w), xyz are + * temporaries. If not written, + * interpolated depth is used? + */ +#define REG_TYPE_U 6 /* unpreserved temporaries */ +#define REG_TYPE_MASK 0x7 +#define REG_NR_MASK 0xf + +/* REG_TYPE_T: + */ +#define T_TEX0 0 +#define T_TEX1 1 +#define T_TEX2 2 +#define T_TEX3 3 +#define T_TEX4 4 +#define T_TEX5 5 +#define T_TEX6 6 +#define T_TEX7 7 +#define T_DIFFUSE 8 +#define T_SPECULAR 9 +#define T_FOG_W 10 /* interpolated fog is in W coord */ + +/* Arithmetic instructions */ + +/* .replicate_swizzle == selection and replication of a particular + * scalar channel, ie., .xxxx, .yyyy, .zzzz or .wwww + */ +#define A0_NOP (0x0<<24) /* no operation */ +#define A0_ADD (0x1<<24) /* dst = src0 + src1 */ +#define A0_MOV (0x2<<24) /* dst = src0 */ +#define A0_MUL (0x3<<24) /* dst = src0 * src1 */ +#define A0_MAD (0x4<<24) /* dst = src0 * src1 + src2 */ +#define A0_DP2ADD (0x5<<24) /* dst.xyzw = src0.xy dot src1.xy + src2.replicate_swizzle */ +#define A0_DP3 (0x6<<24) /* dst.xyzw = src0.xyz dot src1.xyz */ +#define A0_DP4 (0x7<<24) /* dst.xyzw = src0.xyzw dot src1.xyzw */ +#define A0_FRC (0x8<<24) /* dst = src0 - floor(src0) */ +#define A0_RCP (0x9<<24) /* dst.xyzw = 1/(src0.replicate_swizzle) */ +#define A0_RSQ (0xa<<24) /* dst.xyzw = 1/(sqrt(abs(src0.replicate_swizzle))) */ +#define A0_EXP (0xb<<24) /* dst.xyzw = exp2(src0.replicate_swizzle) */ +#define A0_LOG (0xc<<24) /* dst.xyzw = log2(abs(src0.replicate_swizzle)) */ +#define A0_CMP (0xd<<24) /* dst = (src0 >= 0.0) ? src1 : src2 */ +#define A0_MIN (0xe<<24) /* dst = (src0 < src1) ? src0 : src1 */ +#define A0_MAX (0xf<<24) /* dst = (src0 >= src1) ? src0 : src1 */ +#define A0_FLR (0x10<<24) /* dst = floor(src0) */ +#define A0_MOD (0x11<<24) /* dst = src0 fmod 1.0 */ +#define A0_TRC (0x12<<24) /* dst = int(src0) */ +#define A0_SGE (0x13<<24) /* dst = src0 >= src1 ? 1.0 : 0.0 */ +#define A0_SLT (0x14<<24) /* dst = src0 < src1 ? 1.0 : 0.0 */ +#define A0_DEST_SATURATE (1<<22) +#define A0_DEST_TYPE_SHIFT 19 +/* Allow: R, OC, OD, U */ +#define A0_DEST_NR_SHIFT 14 +/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */ +#define A0_DEST_CHANNEL_X (1<<10) +#define A0_DEST_CHANNEL_Y (2<<10) +#define A0_DEST_CHANNEL_Z (4<<10) +#define A0_DEST_CHANNEL_W (8<<10) +#define A0_DEST_CHANNEL_ALL (0xf<<10) +#define A0_DEST_CHANNEL_SHIFT 10 +#define A0_SRC0_TYPE_SHIFT 7 +#define A0_SRC0_NR_SHIFT 2 + +#define A0_DEST_CHANNEL_XY (A0_DEST_CHANNEL_X|A0_DEST_CHANNEL_Y) +#define A0_DEST_CHANNEL_XYZ (A0_DEST_CHANNEL_XY|A0_DEST_CHANNEL_Z) + +#define SRC_X 0 +#define SRC_Y 1 +#define SRC_Z 2 +#define SRC_W 3 +#define SRC_ZERO 4 +#define SRC_ONE 5 + +#define A1_SRC0_CHANNEL_X_NEGATE (1<<31) +#define A1_SRC0_CHANNEL_X_SHIFT 28 +#define A1_SRC0_CHANNEL_Y_NEGATE (1<<27) +#define A1_SRC0_CHANNEL_Y_SHIFT 24 +#define A1_SRC0_CHANNEL_Z_NEGATE (1<<23) +#define A1_SRC0_CHANNEL_Z_SHIFT 20 +#define A1_SRC0_CHANNEL_W_NEGATE (1<<19) +#define A1_SRC0_CHANNEL_W_SHIFT 16 +#define A1_SRC1_TYPE_SHIFT 13 +#define A1_SRC1_NR_SHIFT 8 +#define A1_SRC1_CHANNEL_X_NEGATE (1<<7) +#define A1_SRC1_CHANNEL_X_SHIFT 4 +#define A1_SRC1_CHANNEL_Y_NEGATE (1<<3) +#define A1_SRC1_CHANNEL_Y_SHIFT 0 + +#define A2_SRC1_CHANNEL_Z_NEGATE (1<<31) +#define A2_SRC1_CHANNEL_Z_SHIFT 28 +#define A2_SRC1_CHANNEL_W_NEGATE (1<<27) +#define A2_SRC1_CHANNEL_W_SHIFT 24 +#define A2_SRC2_TYPE_SHIFT 21 +#define A2_SRC2_NR_SHIFT 16 +#define A2_SRC2_CHANNEL_X_NEGATE (1<<15) +#define A2_SRC2_CHANNEL_X_SHIFT 12 +#define A2_SRC2_CHANNEL_Y_NEGATE (1<<11) +#define A2_SRC2_CHANNEL_Y_SHIFT 8 +#define A2_SRC2_CHANNEL_Z_NEGATE (1<<7) +#define A2_SRC2_CHANNEL_Z_SHIFT 4 +#define A2_SRC2_CHANNEL_W_NEGATE (1<<3) +#define A2_SRC2_CHANNEL_W_SHIFT 0 + +/* Texture instructions */ +#define T0_TEXLD (0x15<<24) /* Sample texture using predeclared + * sampler and address, and output + * filtered texel data to destination + * register */ +#define T0_TEXLDP (0x16<<24) /* Same as texld but performs a + * perspective divide of the texture + * coordinate .xyz values by .w before + * sampling. */ +#define T0_TEXLDB (0x17<<24) /* Same as texld but biases the + * computed LOD by w. Only S4.6 two's + * comp is used. This implies that a + * float to fixed conversion is + * done. */ +#define T0_TEXKILL (0x18<<24) /* Does not perform a sampling + * operation. Simply kills the pixel + * if any channel of the address + * register is < 0.0. */ +#define T0_DEST_TYPE_SHIFT 19 +/* Allow: R, OC, OD, U */ +/* Note: U (unpreserved) regs do not retain their values between + * phases (cannot be used for feedback) + * + * Note: oC and OD registers can only be used as the destination of a + * texture instruction once per phase (this is an implementation + * restriction). + */ +#define T0_DEST_NR_SHIFT 14 +/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */ +#define T0_SAMPLER_NR_SHIFT 0 /* This field ignored for TEXKILL */ +#define T0_SAMPLER_NR_MASK (0xf<<0) + +#define T1_ADDRESS_REG_TYPE_SHIFT 24 /* Reg to use as texture coord */ +/* Allow R, T, OC, OD -- R, OC, OD are 'dependent' reads, new program phase */ +#define T1_ADDRESS_REG_NR_SHIFT 17 +#define T2_MBZ 0 + +/* Declaration instructions */ +#define D0_DCL (0x19<<24) /* Declare a t (interpolated attrib) + * register or an s (sampler) + * register. */ +#define D0_SAMPLE_TYPE_SHIFT 22 +#define D0_SAMPLE_TYPE_2D (0x0<<22) +#define D0_SAMPLE_TYPE_CUBE (0x1<<22) +#define D0_SAMPLE_TYPE_VOLUME (0x2<<22) +#define D0_SAMPLE_TYPE_MASK (0x3<<22) + +#define D0_TYPE_SHIFT 19 +/* Allow: T, S */ +#define D0_NR_SHIFT 14 +/* Allow T: 0..10, S: 0..15 */ +#define D0_CHANNEL_X (1<<10) +#define D0_CHANNEL_Y (2<<10) +#define D0_CHANNEL_Z (4<<10) +#define D0_CHANNEL_W (8<<10) +#define D0_CHANNEL_ALL (0xf<<10) +#define D0_CHANNEL_NONE (0<<10) + +#define D0_CHANNEL_XY (D0_CHANNEL_X|D0_CHANNEL_Y) +#define D0_CHANNEL_XYZ (D0_CHANNEL_XY|D0_CHANNEL_Z) + +/* I915 Errata: Do not allow (xz), (xw), (xzw) combinations for diffuse + * or specular declarations. + * + * For T dcls, only allow: (x), (xy), (xyz), (w), (xyzw) + * + * Must be zero for S (sampler) dcls + */ +#define D1_MBZ 0 +#define D2_MBZ 0 + +/* p207. + * The DWORD count is 3 times the number of bits set in MS1_MAPMASK_MASK + */ +#define _3DSTATE_MAP_STATE (CMD_3D|(0x1d<<24)|(0x0<<16)) + +#define MS1_MAPMASK_SHIFT 0 +#define MS1_MAPMASK_MASK (0x8fff<<0) + +#define MS2_UNTRUSTED_SURFACE (1<<31) +#define MS2_ADDRESS_MASK 0xfffffffc +#define MS2_VERTICAL_LINE_STRIDE (1<<1) +#define MS2_VERTICAL_OFFSET (1<<1) + +#define MS3_HEIGHT_SHIFT 21 +#define MS3_WIDTH_SHIFT 10 +#define MS3_PALETTE_SELECT (1<<9) +#define MS3_MAPSURF_FORMAT_SHIFT 7 +#define MS3_MAPSURF_FORMAT_MASK (0x7<<7) +#define MAPSURF_8BIT (1<<7) +#define MAPSURF_16BIT (2<<7) +#define MAPSURF_32BIT (3<<7) +#define MAPSURF_422 (5<<7) +#define MAPSURF_COMPRESSED (6<<7) +#define MAPSURF_4BIT_INDEXED (7<<7) +#define MS3_MT_FORMAT_MASK (0x7 << 3) +#define MS3_MT_FORMAT_SHIFT 3 +#define MT_4BIT_IDX_ARGB8888 (7<<3) /* SURFACE_4BIT_INDEXED */ +#define MT_8BIT_I8 (0<<3) /* SURFACE_8BIT */ +#define MT_8BIT_L8 (1<<3) +#define MT_8BIT_A8 (4<<3) +#define MT_8BIT_MONO8 (5<<3) +#define MT_16BIT_RGB565 (0<<3) /* SURFACE_16BIT */ +#define MT_16BIT_ARGB1555 (1<<3) +#define MT_16BIT_ARGB4444 (2<<3) +#define MT_16BIT_AY88 (3<<3) +#define MT_16BIT_88DVDU (5<<3) +#define MT_16BIT_BUMP_655LDVDU (6<<3) +#define MT_16BIT_I16 (7<<3) +#define MT_16BIT_L16 (8<<3) +#define MT_16BIT_A16 (9<<3) +#define MT_32BIT_ARGB8888 (0<<3) /* SURFACE_32BIT */ +#define MT_32BIT_ABGR8888 (1<<3) +#define MT_32BIT_XRGB8888 (2<<3) +#define MT_32BIT_XBGR8888 (3<<3) +#define MT_32BIT_QWVU8888 (4<<3) +#define MT_32BIT_AXVU8888 (5<<3) +#define MT_32BIT_LXVU8888 (6<<3) +#define MT_32BIT_XLVU8888 (7<<3) +#define MT_32BIT_ARGB2101010 (8<<3) +#define MT_32BIT_ABGR2101010 (9<<3) +#define MT_32BIT_AWVU2101010 (0xA<<3) +#define MT_32BIT_GR1616 (0xB<<3) +#define MT_32BIT_VU1616 (0xC<<3) +#define MT_32BIT_xI824 (0xD<<3) +#define MT_32BIT_xA824 (0xE<<3) +#define MT_32BIT_xL824 (0xF<<3) +#define MT_422_YCRCB_SWAPY (0<<3) /* SURFACE_422 */ +#define MT_422_YCRCB_NORMAL (1<<3) +#define MT_422_YCRCB_SWAPUV (2<<3) +#define MT_422_YCRCB_SWAPUVY (3<<3) +#define MT_COMPRESS_DXT1 (0<<3) /* SURFACE_COMPRESSED */ +#define MT_COMPRESS_DXT2_3 (1<<3) +#define MT_COMPRESS_DXT4_5 (2<<3) +#define MT_COMPRESS_FXT1 (3<<3) +#define MT_COMPRESS_DXT1_RGB (4<<3) +#define MS3_USE_FENCE_REGS (1<<2) +#define MS3_TILED_SURFACE (1<<1) +#define MS3_TILE_WALK (1<<0) + +/* The pitch is the pitch measured in DWORDS, minus 1 */ +#define MS4_PITCH_SHIFT 21 +#define MS4_CUBE_FACE_ENA_NEGX (1<<20) +#define MS4_CUBE_FACE_ENA_POSX (1<<19) +#define MS4_CUBE_FACE_ENA_NEGY (1<<18) +#define MS4_CUBE_FACE_ENA_POSY (1<<17) +#define MS4_CUBE_FACE_ENA_NEGZ (1<<16) +#define MS4_CUBE_FACE_ENA_POSZ (1<<15) +#define MS4_CUBE_FACE_ENA_MASK (0x3f<<15) +#define MS4_MAX_LOD_SHIFT 9 +#define MS4_MAX_LOD_MASK (0x3f<<9) +#define MS4_MIP_LAYOUT_LEGACY (0<<8) +#define MS4_MIP_LAYOUT_BELOW_LPT (0<<8) +#define MS4_MIP_LAYOUT_RIGHT_LPT (1<<8) +#define MS4_VOLUME_DEPTH_SHIFT 0 +#define MS4_VOLUME_DEPTH_MASK (0xff<<0) + +/* p244. + * The DWORD count is 3 times the number of bits set in SS1_MAPMASK_MASK. + */ +#define _3DSTATE_SAMPLER_STATE (CMD_3D|(0x1d<<24)|(0x1<<16)) + +#define SS1_MAPMASK_SHIFT 0 +#define SS1_MAPMASK_MASK (0x8fff<<0) + +#define SS2_REVERSE_GAMMA_ENABLE (1<<31) +#define SS2_PACKED_TO_PLANAR_ENABLE (1<<30) +#define SS2_COLORSPACE_CONVERSION (1<<29) +#define SS2_CHROMAKEY_SHIFT 27 +#define SS2_BASE_MIP_LEVEL_SHIFT 22 +#define SS2_BASE_MIP_LEVEL_MASK (0x1f<<22) +#define SS2_MIP_FILTER_SHIFT 20 +#define SS2_MIP_FILTER_MASK (0x3<<20) +#define MIPFILTER_NONE 0 +#define MIPFILTER_NEAREST 1 +#define MIPFILTER_LINEAR 3 +#define SS2_MAG_FILTER_SHIFT 17 +#define SS2_MAG_FILTER_MASK (0x7<<17) +#define FILTER_NEAREST 0 +#define FILTER_LINEAR 1 +#define FILTER_ANISOTROPIC 2 +#define FILTER_4X4_1 3 +#define FILTER_4X4_2 4 +#define FILTER_4X4_FLAT 5 +#define FILTER_6X5_MONO 6 /* XXX - check */ +#define SS2_MIN_FILTER_SHIFT 14 +#define SS2_MIN_FILTER_MASK (0x7<<14) +#define SS2_LOD_BIAS_SHIFT 5 +#define SS2_LOD_BIAS_ONE (0x10<<5) +#define SS2_LOD_BIAS_MASK (0x1ff<<5) +/* Shadow requires: + * MT_X8{I,L,A}24 or MT_{I,L,A}16 texture format + * FILTER_4X4_x MIN and MAG filters + */ +#define SS2_SHADOW_ENABLE (1<<4) +#define SS2_MAX_ANISO_MASK (1<<3) +#define SS2_MAX_ANISO_2 (0<<3) +#define SS2_MAX_ANISO_4 (1<<3) +#define SS2_SHADOW_FUNC_SHIFT 0 +#define SS2_SHADOW_FUNC_MASK (0x7<<0) +/* SS2_SHADOW_FUNC values: see COMPAREFUNC_* */ + +#define SS3_MIN_LOD_SHIFT 24 +#define SS3_MIN_LOD_ONE (0x10<<24) +#define SS3_MIN_LOD_MASK (0xff<<24) +#define SS3_KILL_PIXEL_ENABLE (1<<17) +#define SS3_TCX_ADDR_MODE_SHIFT 12 +#define SS3_TCX_ADDR_MODE_MASK (0x7<<12) +#define TEXCOORDMODE_WRAP 0 +#define TEXCOORDMODE_MIRROR 1 +#define TEXCOORDMODE_CLAMP_EDGE 2 +#define TEXCOORDMODE_CUBE 3 +#define TEXCOORDMODE_CLAMP_BORDER 4 +#define TEXCOORDMODE_MIRROR_ONCE 5 +#define SS3_TCY_ADDR_MODE_SHIFT 9 +#define SS3_TCY_ADDR_MODE_MASK (0x7<<9) +#define SS3_TCZ_ADDR_MODE_SHIFT 6 +#define SS3_TCZ_ADDR_MODE_MASK (0x7<<6) +#define SS3_NORMALIZED_COORDS (1<<5) +#define SS3_TEXTUREMAP_INDEX_SHIFT 1 +#define SS3_TEXTUREMAP_INDEX_MASK (0xf<<1) +#define SS3_DEINTERLACER_ENABLE (1<<0) + +#define SS4_BORDER_COLOR_MASK (~0) + +/* 3DSTATE_SPAN_STIPPLE, p258 + */ +#define _3DSTATE_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define ST1_ENABLE (1<<16) +#define ST1_MASK (0xffff) + +#define FLUSH_MAP_CACHE (1<<0) +#define FLUSH_RENDER_CACHE (1<<1) + +#endif diff --git a/lib/instdone.c b/lib/instdone.c new file mode 100644 index 00000000..4679a9c1 --- /dev/null +++ b/lib/instdone.c @@ -0,0 +1,358 @@ +/* + * Copyright © 2007,2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <assert.h> +#include "instdone.h" + +#include "intel_chipset.h" +#include "intel_reg.h" + +struct instdone_bit instdone_bits[MAX_INSTDONE_BITS]; +int num_instdone_bits = 0; + +static void +add_instdone_bit(uint32_t reg, uint32_t bit, const char *name) +{ + instdone_bits[num_instdone_bits].reg = reg; + instdone_bits[num_instdone_bits].bit = bit; + instdone_bits[num_instdone_bits].name = name; + num_instdone_bits++; +} + +static void +gen3_instdone_bit(uint32_t bit, const char *name) +{ + add_instdone_bit(INST_DONE, bit, name); +} + +static void +gen4_instdone_bit(uint32_t bit, const char *name) +{ + add_instdone_bit(INST_DONE_I965, bit, name); +} + +static void +gen4_instdone1_bit(uint32_t bit, const char *name) +{ + add_instdone_bit(INST_DONE_1, bit, name); +} + +static void +gen6_instdone1_bit(uint32_t bit, const char *name) +{ + add_instdone_bit(GEN6_INSTDONE_1, bit, name); +} + +static void +gen6_instdone2_bit(uint32_t bit, const char *name) +{ + add_instdone_bit(GEN6_INSTDONE_2, bit, name); +} + +static void +init_g965_instdone1(void) +{ + gen4_instdone1_bit(I965_GW_CS_DONE_CR, "GW CS CR"); + gen4_instdone1_bit(I965_SVSM_CS_DONE_CR, "SVSM CS CR"); + gen4_instdone1_bit(I965_SVDW_CS_DONE_CR, "SVDW CS CR"); + gen4_instdone1_bit(I965_SVDR_CS_DONE_CR, "SVDR CS CR"); + gen4_instdone1_bit(I965_SVRW_CS_DONE_CR, "SVRW CS CR"); + gen4_instdone1_bit(I965_SVRR_CS_DONE_CR, "SVRR CS CR"); + gen4_instdone1_bit(I965_SVTW_CS_DONE_CR, "SVTW CS CR"); + gen4_instdone1_bit(I965_MASM_CS_DONE_CR, "MASM CS CR"); + gen4_instdone1_bit(I965_MASF_CS_DONE_CR, "MASF CS CR"); + gen4_instdone1_bit(I965_MAW_CS_DONE_CR, "MAW CS CR"); + gen4_instdone1_bit(I965_EM1_CS_DONE_CR, "EM1 CS CR"); + gen4_instdone1_bit(I965_EM0_CS_DONE_CR, "EM0 CS CR"); + gen4_instdone1_bit(I965_UC1_CS_DONE, "UC1 CS"); + gen4_instdone1_bit(I965_UC0_CS_DONE, "UC0 CS"); + gen4_instdone1_bit(I965_URB_CS_DONE, "URB CS"); + gen4_instdone1_bit(I965_ISC_CS_DONE, "ISC CS"); + gen4_instdone1_bit(I965_CL_CS_DONE, "CL CS"); + gen4_instdone1_bit(I965_GS_CS_DONE, "GS CS"); + gen4_instdone1_bit(I965_VS0_CS_DONE, "VS0 CS"); + gen4_instdone1_bit(I965_VF_CS_DONE, "VF CS"); +} + +static void +init_g4x_instdone1(void) +{ + gen4_instdone1_bit(G4X_BCS_DONE, "BCS"); + gen4_instdone1_bit(G4X_CS_DONE, "CS"); + gen4_instdone1_bit(G4X_MASF_DONE, "MASF"); + gen4_instdone1_bit(G4X_SVDW_DONE, "SVDW"); + gen4_instdone1_bit(G4X_SVDR_DONE, "SVDR"); + gen4_instdone1_bit(G4X_SVRW_DONE, "SVRW"); + gen4_instdone1_bit(G4X_SVRR_DONE, "SVRR"); + gen4_instdone1_bit(G4X_ISC_DONE, "ISC"); + gen4_instdone1_bit(G4X_MT_DONE, "MT"); + gen4_instdone1_bit(G4X_RC_DONE, "RC"); + gen4_instdone1_bit(G4X_DAP_DONE, "DAP"); + gen4_instdone1_bit(G4X_MAWB_DONE, "MAWB"); + gen4_instdone1_bit(G4X_MT_IDLE, "MT idle"); + //gen4_instdone1_bit(G4X_GBLT_BUSY, "GBLT"); + gen4_instdone1_bit(G4X_SVSM_DONE, "SVSM"); + gen4_instdone1_bit(G4X_MASM_DONE, "MASM"); + gen4_instdone1_bit(G4X_QC_DONE, "QC"); + gen4_instdone1_bit(G4X_FL_DONE, "FL"); + gen4_instdone1_bit(G4X_SC_DONE, "SC"); + gen4_instdone1_bit(G4X_DM_DONE, "DM"); + gen4_instdone1_bit(G4X_FT_DONE, "FT"); + gen4_instdone1_bit(G4X_DG_DONE, "DG"); + gen4_instdone1_bit(G4X_SI_DONE, "SI"); + gen4_instdone1_bit(G4X_SO_DONE, "SO"); + gen4_instdone1_bit(G4X_PL_DONE, "PL"); + gen4_instdone1_bit(G4X_WIZ_DONE, "WIZ"); + gen4_instdone1_bit(G4X_URB_DONE, "URB"); + gen4_instdone1_bit(G4X_SF_DONE, "SF"); + gen4_instdone1_bit(G4X_CL_DONE, "CL"); + gen4_instdone1_bit(G4X_GS_DONE, "GS"); + gen4_instdone1_bit(G4X_VS0_DONE, "VS0"); + gen4_instdone1_bit(G4X_VF_DONE, "VF"); +} + +static void +init_gen7_instdone(void) +{ + gen6_instdone1_bit(1 << 19, "GAM"); + gen6_instdone1_bit(1 << 18, "GAFM"); + gen6_instdone1_bit(1 << 17, "TSG"); + gen6_instdone1_bit(1 << 16, "VFE"); + gen6_instdone1_bit(1 << 15, "GAFS"); + gen6_instdone1_bit(1 << 14, "SVG"); + gen6_instdone1_bit(1 << 13, "URBM"); + gen6_instdone1_bit(1 << 12, "TDG"); + gen6_instdone1_bit(1 << 9, "SF"); + gen6_instdone1_bit(1 << 8, "CL"); + gen6_instdone1_bit(1 << 7, "SOL"); + gen6_instdone1_bit(1 << 6, "GS"); + gen6_instdone1_bit(1 << 5, "DS"); + gen6_instdone1_bit(1 << 4, "TE"); + gen6_instdone1_bit(1 << 3, "HS"); + gen6_instdone1_bit(1 << 2, "VS"); + gen6_instdone1_bit(1 << 1, "VF"); +} + +void +init_instdone_definitions(uint32_t devid) +{ + if (IS_GEN7(devid)) { + init_gen7_instdone(); + } else if (IS_GEN6(devid)) { + /* Now called INSTDONE_1 in the docs. */ + gen6_instdone1_bit(GEN6_MA_3_DONE, "Message Arbiter 3"); + gen6_instdone1_bit(GEN6_EU_32_DONE, "EU 32"); + gen6_instdone1_bit(GEN6_EU_31_DONE, "EU 31"); + gen6_instdone1_bit(GEN6_EU_30_DONE, "EU 30"); + gen6_instdone1_bit(GEN6_MA_3_DONE, "Message Arbiter 2"); + gen6_instdone1_bit(GEN6_EU_22_DONE, "EU 22"); + gen6_instdone1_bit(GEN6_EU_21_DONE, "EU 21"); + gen6_instdone1_bit(GEN6_EU_20_DONE, "EU 20"); + gen6_instdone1_bit(GEN6_MA_3_DONE, "Message Arbiter 1"); + gen6_instdone1_bit(GEN6_EU_12_DONE, "EU 12"); + gen6_instdone1_bit(GEN6_EU_11_DONE, "EU 11"); + gen6_instdone1_bit(GEN6_EU_10_DONE, "EU 10"); + gen6_instdone1_bit(GEN6_MA_3_DONE, "Message Arbiter 0"); + gen6_instdone1_bit(GEN6_EU_02_DONE, "EU 02"); + gen6_instdone1_bit(GEN6_EU_01_DONE, "EU 01"); + gen6_instdone1_bit(GEN6_EU_00_DONE, "EU 00"); + + gen6_instdone1_bit(GEN6_IC_3_DONE, "IC 3"); + gen6_instdone1_bit(GEN6_IC_2_DONE, "IC 2"); + gen6_instdone1_bit(GEN6_IC_1_DONE, "IC 1"); + gen6_instdone1_bit(GEN6_IC_0_DONE, "IC 0"); + gen6_instdone1_bit(GEN6_ISC_10_DONE, "ISC 1/0"); + gen6_instdone1_bit(GEN6_ISC_32_DONE, "ISC 3/2"); + + gen6_instdone1_bit(GEN6_VSC_DONE, "VSC"); + gen6_instdone1_bit(GEN6_IEF_DONE, "IEF"); + gen6_instdone1_bit(GEN6_VFE_DONE, "VFE"); + gen6_instdone1_bit(GEN6_TD_DONE, "TD"); + gen6_instdone1_bit(GEN6_TS_DONE, "TS"); + gen6_instdone1_bit(GEN6_GW_DONE, "GW"); + gen6_instdone1_bit(GEN6_HIZ_DONE, "HIZ"); + gen6_instdone1_bit(GEN6_AVS_DONE, "AVS"); + + /* Now called INSTDONE_2 in the docs. */ + gen6_instdone2_bit(GEN6_GAM_DONE, "GAM"); + gen6_instdone2_bit(GEN6_CS_DONE, "CS"); + gen6_instdone2_bit(GEN6_WMBE_DONE, "WMBE"); + gen6_instdone2_bit(GEN6_SVRW_DONE, "SVRW"); + gen6_instdone2_bit(GEN6_RCC_DONE, "RCC"); + gen6_instdone2_bit(GEN6_SVG_DONE, "SVG"); + gen6_instdone2_bit(GEN6_ISC_DONE, "ISC"); + gen6_instdone2_bit(GEN6_MT_DONE, "MT"); + gen6_instdone2_bit(GEN6_RCPFE_DONE, "RCPFE"); + gen6_instdone2_bit(GEN6_RCPBE_DONE, "RCPBE"); + gen6_instdone2_bit(GEN6_VDI_DONE, "VDI"); + gen6_instdone2_bit(GEN6_RCZ_DONE, "RCZ"); + gen6_instdone2_bit(GEN6_DAP_DONE, "DAP"); + gen6_instdone2_bit(GEN6_PSD_DONE, "PSD"); + gen6_instdone2_bit(GEN6_IZ_DONE, "IZ"); + gen6_instdone2_bit(GEN6_WMFE_DONE, "WMFE"); + gen6_instdone2_bit(GEN6_SVSM_DONE, "SVSM"); + gen6_instdone2_bit(GEN6_QC_DONE, "QC"); + gen6_instdone2_bit(GEN6_FL_DONE, "FL"); + gen6_instdone2_bit(GEN6_SC_DONE, "SC"); + gen6_instdone2_bit(GEN6_DM_DONE, "DM"); + gen6_instdone2_bit(GEN6_FT_DONE, "FT"); + gen6_instdone2_bit(GEN6_DG_DONE, "DG"); + gen6_instdone2_bit(GEN6_SI_DONE, "SI"); + gen6_instdone2_bit(GEN6_SO_DONE, "SO"); + gen6_instdone2_bit(GEN6_PL_DONE, "PL"); + gen6_instdone2_bit(GEN6_VME_DONE, "VME"); + gen6_instdone2_bit(GEN6_SF_DONE, "SF"); + gen6_instdone2_bit(GEN6_CL_DONE, "CL"); + gen6_instdone2_bit(GEN6_GS_DONE, "GS"); + gen6_instdone2_bit(GEN6_VS0_DONE, "VS0"); + gen6_instdone2_bit(GEN6_VF_DONE, "VF"); + } else if (IS_GEN5(devid)) { + gen4_instdone_bit(ILK_ROW_0_EU_0_DONE, "Row 0, EU 0"); + gen4_instdone_bit(ILK_ROW_0_EU_1_DONE, "Row 0, EU 1"); + gen4_instdone_bit(ILK_ROW_0_EU_2_DONE, "Row 0, EU 2"); + gen4_instdone_bit(ILK_ROW_0_EU_3_DONE, "Row 0, EU 3"); + gen4_instdone_bit(ILK_ROW_1_EU_0_DONE, "Row 1, EU 0"); + gen4_instdone_bit(ILK_ROW_1_EU_1_DONE, "Row 1, EU 1"); + gen4_instdone_bit(ILK_ROW_1_EU_2_DONE, "Row 1, EU 2"); + gen4_instdone_bit(ILK_ROW_1_EU_3_DONE, "Row 1, EU 3"); + gen4_instdone_bit(ILK_ROW_2_EU_0_DONE, "Row 2, EU 0"); + gen4_instdone_bit(ILK_ROW_2_EU_1_DONE, "Row 2, EU 1"); + gen4_instdone_bit(ILK_ROW_2_EU_2_DONE, "Row 2, EU 2"); + gen4_instdone_bit(ILK_ROW_2_EU_3_DONE, "Row 2, EU 3"); + gen4_instdone_bit(ILK_VCP_DONE, "VCP"); + gen4_instdone_bit(ILK_ROW_0_MATH_DONE, "Row 0 math"); + gen4_instdone_bit(ILK_ROW_1_MATH_DONE, "Row 1 math"); + gen4_instdone_bit(ILK_ROW_2_MATH_DONE, "Row 2 math"); + gen4_instdone_bit(ILK_VC1_DONE, "VC1"); + gen4_instdone_bit(ILK_ROW_0_MA_DONE, "Row 0 MA"); + gen4_instdone_bit(ILK_ROW_1_MA_DONE, "Row 1 MA"); + gen4_instdone_bit(ILK_ROW_2_MA_DONE, "Row 2 MA"); + gen4_instdone_bit(ILK_ROW_0_ISC_DONE, "Row 0 ISC"); + gen4_instdone_bit(ILK_ROW_1_ISC_DONE, "Row 1 ISC"); + gen4_instdone_bit(ILK_ROW_2_ISC_DONE, "Row 2 ISC"); + gen4_instdone_bit(ILK_VFE_DONE, "VFE"); + gen4_instdone_bit(ILK_TD_DONE, "TD"); + gen4_instdone_bit(ILK_SVTS_DONE, "SVTS"); + gen4_instdone_bit(ILK_TS_DONE, "TS"); + gen4_instdone_bit(ILK_GW_DONE, "GW"); + gen4_instdone_bit(ILK_AI_DONE, "AI"); + gen4_instdone_bit(ILK_AC_DONE, "AC"); + gen4_instdone_bit(ILK_AM_DONE, "AM"); + + init_g4x_instdone1(); + } else if (IS_GEN4(devid)) { + gen4_instdone_bit(I965_ROW_0_EU_0_DONE, "Row 0, EU 0"); + gen4_instdone_bit(I965_ROW_0_EU_1_DONE, "Row 0, EU 1"); + gen4_instdone_bit(I965_ROW_0_EU_2_DONE, "Row 0, EU 2"); + gen4_instdone_bit(I965_ROW_0_EU_3_DONE, "Row 0, EU 3"); + gen4_instdone_bit(I965_ROW_1_EU_0_DONE, "Row 1, EU 0"); + gen4_instdone_bit(I965_ROW_1_EU_1_DONE, "Row 1, EU 1"); + gen4_instdone_bit(I965_ROW_1_EU_2_DONE, "Row 1, EU 2"); + gen4_instdone_bit(I965_ROW_1_EU_3_DONE, "Row 1, EU 3"); + gen4_instdone_bit(I965_SF_DONE, "Strips and Fans"); + gen4_instdone_bit(I965_SE_DONE, "Setup Engine"); + gen4_instdone_bit(I965_WM_DONE, "Windowizer"); + gen4_instdone_bit(I965_DISPATCHER_DONE, "Dispatcher"); + gen4_instdone_bit(I965_PROJECTION_DONE, "Projection and LOD"); + gen4_instdone_bit(I965_DG_DONE, "Dependent address generator"); + gen4_instdone_bit(I965_QUAD_CACHE_DONE, "Texture fetch"); + gen4_instdone_bit(I965_TEXTURE_FETCH_DONE, "Texture fetch"); + gen4_instdone_bit(I965_TEXTURE_DECOMPRESS_DONE, "Texture decompress"); + gen4_instdone_bit(I965_SAMPLER_CACHE_DONE, "Sampler cache"); + gen4_instdone_bit(I965_FILTER_DONE, "Filtering"); + gen4_instdone_bit(I965_BYPASS_DONE, "Bypass FIFO"); + gen4_instdone_bit(I965_PS_DONE, "Pixel shader"); + gen4_instdone_bit(I965_CC_DONE, "Color calculator"); + gen4_instdone_bit(I965_MAP_FILTER_DONE, "Map filter"); + gen4_instdone_bit(I965_MAP_L2_IDLE, "Map L2"); + gen4_instdone_bit(I965_MA_ROW_0_DONE, "Message Arbiter row 0"); + gen4_instdone_bit(I965_MA_ROW_1_DONE, "Message Arbiter row 1"); + gen4_instdone_bit(I965_IC_ROW_0_DONE, "Instruction cache row 0"); + gen4_instdone_bit(I965_IC_ROW_1_DONE, "Instruction cache row 1"); + gen4_instdone_bit(I965_CP_DONE, "Command Processor"); + + if (IS_G4X(devid)) { + init_g4x_instdone1(); + } else { + init_g965_instdone1(); + } + } else if (IS_GEN3(devid)) { + gen3_instdone_bit(IDCT_DONE, "IDCT"); + gen3_instdone_bit(IQ_DONE, "IQ"); + gen3_instdone_bit(PR_DONE, "PR"); + gen3_instdone_bit(VLD_DONE, "VLD"); + gen3_instdone_bit(IP_DONE, "Instruction parser"); + gen3_instdone_bit(FBC_DONE, "Framebuffer Compression"); + gen3_instdone_bit(BINNER_DONE, "Binner"); + gen3_instdone_bit(SF_DONE, "Strips and fans"); + gen3_instdone_bit(SE_DONE, "Setup engine"); + gen3_instdone_bit(WM_DONE, "Windowizer"); + gen3_instdone_bit(IZ_DONE, "Intermediate Z"); + gen3_instdone_bit(PERSPECTIVE_INTERP_DONE, "Perspective interpolation"); + gen3_instdone_bit(DISPATCHER_DONE, "Dispatcher"); + gen3_instdone_bit(PROJECTION_DONE, "Projection and LOD"); + gen3_instdone_bit(DEPENDENT_ADDRESS_DONE, "Dependent address calculation"); + gen3_instdone_bit(TEXTURE_FETCH_DONE, "Texture fetch"); + gen3_instdone_bit(TEXTURE_DECOMPRESS_DONE, "Texture decompression"); + gen3_instdone_bit(SAMPLER_CACHE_DONE, "Sampler Cache"); + gen3_instdone_bit(FILTER_DONE, "Filtering"); + gen3_instdone_bit(BYPASS_FIFO_DONE, "Bypass FIFO"); + gen3_instdone_bit(PS_DONE, "Pixel shader"); + gen3_instdone_bit(CC_DONE, "Color calculator"); + gen3_instdone_bit(MAP_FILTER_DONE, "Map filter"); + gen3_instdone_bit(MAP_L2_IDLE, "Map L2"); + } else { + assert(IS_GEN2(devid)); + gen3_instdone_bit(I830_GMBUS_DONE, "GMBUS"); + gen3_instdone_bit(I830_FBC_DONE, "FBC"); + gen3_instdone_bit(I830_BINNER_DONE, "BINNER"); + gen3_instdone_bit(I830_MPEG_DONE, "MPEG"); + gen3_instdone_bit(I830_MECO_DONE, "MECO"); + gen3_instdone_bit(I830_MCD_DONE, "MCD"); + gen3_instdone_bit(I830_MCSTP_DONE, "MCSTP"); + gen3_instdone_bit(I830_CC_DONE, "CC"); + gen3_instdone_bit(I830_DG_DONE, "DG"); + gen3_instdone_bit(I830_DCMP_DONE, "DCMP"); + gen3_instdone_bit(I830_FTCH_DONE, "FTCH"); + gen3_instdone_bit(I830_IT_DONE, "IT"); + gen3_instdone_bit(I830_MG_DONE, "MG"); + gen3_instdone_bit(I830_MEC_DONE, "MEC"); + gen3_instdone_bit(I830_PC_DONE, "PC"); + gen3_instdone_bit(I830_QCC_DONE, "QCC"); + gen3_instdone_bit(I830_TB_DONE, "TB"); + gen3_instdone_bit(I830_WM_DONE, "WM"); + gen3_instdone_bit(I830_EF_DONE, "EF"); + gen3_instdone_bit(I830_BLITTER_DONE, "Blitter"); + gen3_instdone_bit(I830_MAP_L2_DONE, "Map L2 cache"); + gen3_instdone_bit(I830_SECONDARY_RING_3_DONE, "Secondary ring 3"); + gen3_instdone_bit(I830_SECONDARY_RING_2_DONE, "Secondary ring 2"); + gen3_instdone_bit(I830_SECONDARY_RING_1_DONE, "Secondary ring 1"); + gen3_instdone_bit(I830_SECONDARY_RING_0_DONE, "Secondary ring 0"); + gen3_instdone_bit(I830_PRIMARY_RING_1_DONE, "Primary ring 1"); + gen3_instdone_bit(I830_PRIMARY_RING_0_DONE, "Primary ring 0"); + } +} diff --git a/lib/instdone.h b/lib/instdone.h new file mode 100644 index 00000000..c86a54a7 --- /dev/null +++ b/lib/instdone.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2007,2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <stdint.h> + +#define MAX_INSTDONE_BITS 100 + +struct instdone_bit { + uint32_t reg; + uint32_t bit; + const char *name; +}; + +extern struct instdone_bit instdone_bits[MAX_INSTDONE_BITS]; +extern int num_instdone_bits; + +void init_instdone_definitions(uint32_t devid); diff --git a/lib/intel_batchbuffer.c b/lib/intel_batchbuffer.c new file mode 100644 index 00000000..724e23d9 --- /dev/null +++ b/lib/intel_batchbuffer.c @@ -0,0 +1,241 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 <inttypes.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "drm.h" +#include "drmtest.h" +#include "intel_batchbuffer.h" +#include "intel_bufmgr.h" +#include "intel_chipset.h" +#include "intel_reg.h" +#include <i915_drm.h> + +void +intel_batchbuffer_reset(struct intel_batchbuffer *batch) +{ + if (batch->bo != NULL) { + drm_intel_bo_unreference(batch->bo); + batch->bo = NULL; + } + + batch->bo = drm_intel_bo_alloc(batch->bufmgr, "batchbuffer", + BATCH_SZ, 4096); + + batch->ptr = batch->buffer; +} + +struct intel_batchbuffer * +intel_batchbuffer_alloc(drm_intel_bufmgr *bufmgr, uint32_t devid) +{ + struct intel_batchbuffer *batch = calloc(sizeof(*batch), 1); + + batch->bufmgr = bufmgr; + batch->devid = devid; + intel_batchbuffer_reset(batch); + + return batch; +} + +void +intel_batchbuffer_free(struct intel_batchbuffer *batch) +{ + drm_intel_bo_unreference(batch->bo); + batch->bo = NULL; + free(batch); +} + +#define CMD_POLY_STIPPLE_OFFSET 0x7906 + +static unsigned int +flush_on_ring_common(struct intel_batchbuffer *batch, int ring) +{ + unsigned int used = batch->ptr - batch->buffer; + + if (used == 0) + return 0; + + if (IS_GEN5(batch->devid)) { + /* emit gen5 w/a without batch space checks - we reserve that + * already. */ + *(uint32_t *) (batch->ptr) = CMD_POLY_STIPPLE_OFFSET << 16; + *(uint32_t *) (batch->ptr) = 0; + batch->ptr += 8; + } + + /* Round batchbuffer usage to 2 DWORDs. */ + if ((used & 4) == 0) { + *(uint32_t *) (batch->ptr) = 0; /* noop */ + batch->ptr += 4; + } + + /* Mark the end of the buffer. */ + *(uint32_t *)(batch->ptr) = MI_BATCH_BUFFER_END; /* noop */ + batch->ptr += 4; + return batch->ptr - batch->buffer; +} + +void +intel_batchbuffer_flush_on_ring(struct intel_batchbuffer *batch, int ring) +{ + unsigned int used = flush_on_ring_common(batch, ring); + + if (used == 0) + return; + + do_or_die(drm_intel_bo_subdata(batch->bo, 0, used, batch->buffer)); + + batch->ptr = NULL; + + do_or_die(drm_intel_bo_mrb_exec(batch->bo, used, NULL, 0, 0, ring)); + + intel_batchbuffer_reset(batch); +} + +void +intel_batchbuffer_flush_with_context(struct intel_batchbuffer *batch, + drm_intel_context *context) +{ + int ret; + unsigned int used = flush_on_ring_common(batch, I915_EXEC_RENDER); + + if (used == 0) + return; + + ret = drm_intel_bo_subdata(batch->bo, 0, used, batch->buffer); + assert(ret == 0); + + batch->ptr = NULL; + + ret = drm_intel_gem_bo_context_exec(batch->bo, context, used, + I915_EXEC_RENDER); + assert(ret == 0); + + intel_batchbuffer_reset(batch); +} + +void +intel_batchbuffer_flush(struct intel_batchbuffer *batch) +{ + int ring = 0; + if (HAS_BLT_RING(batch->devid)) + ring = I915_EXEC_BLT; + intel_batchbuffer_flush_on_ring(batch, ring); +} + + +/* This is the only way buffers get added to the validate list. + */ +void +intel_batchbuffer_emit_reloc(struct intel_batchbuffer *batch, + drm_intel_bo *buffer, uint32_t delta, + uint32_t read_domains, uint32_t write_domain, + int fenced) +{ + int ret; + + if (batch->ptr - batch->buffer > BATCH_SZ) + printf("bad relocation ptr %p map %p offset %d size %d\n", + batch->ptr, batch->buffer, + (int)(batch->ptr - batch->buffer), + BATCH_SZ); + + if (fenced) + ret = drm_intel_bo_emit_reloc_fence(batch->bo, batch->ptr - batch->buffer, + buffer, delta, + read_domains, write_domain); + else + ret = drm_intel_bo_emit_reloc(batch->bo, batch->ptr - batch->buffer, + buffer, delta, + read_domains, write_domain); + intel_batchbuffer_emit_dword(batch, buffer->offset + delta); + assert(ret == 0); +} + +void +intel_batchbuffer_data(struct intel_batchbuffer *batch, + const void *data, unsigned int bytes) +{ + assert((bytes & 3) == 0); + intel_batchbuffer_require_space(batch, bytes); + memcpy(batch->ptr, data, bytes); + batch->ptr += bytes; +} + +void +intel_copy_bo(struct intel_batchbuffer *batch, + drm_intel_bo *dst_bo, drm_intel_bo *src_bo, + int width, int height) +{ + uint32_t src_tiling, dst_tiling, swizzle; + uint32_t src_pitch, dst_pitch; + uint32_t cmd_bits = 0; + + drm_intel_bo_get_tiling(src_bo, &src_tiling, &swizzle); + drm_intel_bo_get_tiling(dst_bo, &dst_tiling, &swizzle); + + src_pitch = width * 4; + if (IS_965(batch->devid) && src_tiling != I915_TILING_NONE) { + src_pitch /= 4; + cmd_bits |= XY_SRC_COPY_BLT_SRC_TILED; + } + + dst_pitch = width * 4; + if (IS_965(batch->devid) && dst_tiling != I915_TILING_NONE) { + dst_pitch /= 4; + cmd_bits |= XY_SRC_COPY_BLT_DST_TILED; + } + + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB | + cmd_bits); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + dst_pitch); + OUT_BATCH(0); /* dst x1,y1 */ + OUT_BATCH((height << 16) | width); /* dst x2,y2 */ + OUT_RELOC(dst_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0); /* src x1,y1 */ + OUT_BATCH(src_pitch); + OUT_RELOC(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); +} + +void +intel_batchbuffer_emit_mi_flush(struct intel_batchbuffer *batch) +{ + intel_batchbuffer_require_space(batch, 4); + intel_batchbuffer_emit_dword(batch, MI_FLUSH); +} diff --git a/lib/intel_batchbuffer.h b/lib/intel_batchbuffer.h new file mode 100644 index 00000000..ba0934cb --- /dev/null +++ b/lib/intel_batchbuffer.h @@ -0,0 +1,112 @@ +#ifndef INTEL_BATCHBUFFER_H +#define INTEL_BATCHBUFFER_H + +#include <assert.h> +#include "intel_bufmgr.h" + +#define BATCH_SZ 4096 +#define BATCH_RESERVED 16 + +struct intel_batchbuffer { + drm_intel_bufmgr *bufmgr; + uint32_t devid; + + drm_intel_bo *bo; + + uint8_t buffer[BATCH_SZ]; + uint8_t *ptr; +}; + +struct intel_batchbuffer *intel_batchbuffer_alloc(drm_intel_bufmgr *bufmgr, + uint32_t devid); + +void intel_batchbuffer_free(struct intel_batchbuffer *batch); + + +void intel_batchbuffer_flush(struct intel_batchbuffer *batch); +void intel_batchbuffer_flush_on_ring(struct intel_batchbuffer *batch, int ring); +void intel_batchbuffer_flush_with_context(struct intel_batchbuffer *batch, + drm_intel_context *context); + +void intel_batchbuffer_reset(struct intel_batchbuffer *batch); + +void intel_batchbuffer_data(struct intel_batchbuffer *batch, + const void *data, unsigned int bytes); + +void intel_batchbuffer_emit_reloc(struct intel_batchbuffer *batch, + drm_intel_bo *buffer, + uint32_t delta, + uint32_t read_domains, + uint32_t write_domain, + int fenced); + +/* Inline functions - might actually be better off with these + * non-inlined. Certainly better off switching all command packets to + * be passed as structs rather than dwords, but that's a little bit of + * work... + */ +#pragma GCC diagnostic ignored "-Winline" +static inline int +intel_batchbuffer_space(struct intel_batchbuffer *batch) +{ + return (BATCH_SZ - BATCH_RESERVED) - (batch->ptr - batch->buffer); +} + + +static inline void +intel_batchbuffer_emit_dword(struct intel_batchbuffer *batch, uint32_t dword) +{ + assert(intel_batchbuffer_space(batch) >= 4); + *(uint32_t *) (batch->ptr) = dword; + batch->ptr += 4; +} + +static inline void +intel_batchbuffer_require_space(struct intel_batchbuffer *batch, + unsigned int sz) +{ + assert(sz < BATCH_SZ - BATCH_RESERVED); + if (intel_batchbuffer_space(batch) < sz) + intel_batchbuffer_flush(batch); +} + +/* Here are the crusty old macros, to be removed: + */ +#define BATCH_LOCALS + +#define BEGIN_BATCH(n) do { \ + intel_batchbuffer_require_space(batch, (n)*4); \ +} while (0) + +#define OUT_BATCH(d) intel_batchbuffer_emit_dword(batch, d) + +#define OUT_RELOC_FENCED(buf, read_domains, write_domain, delta) do { \ + assert((delta) >= 0); \ + intel_batchbuffer_emit_reloc(batch, buf, delta, \ + read_domains, write_domain, 1); \ +} while (0) + +#define OUT_RELOC(buf, read_domains, write_domain, delta) do { \ + assert((delta) >= 0); \ + intel_batchbuffer_emit_reloc(batch, buf, delta, \ + read_domains, write_domain, 0); \ +} while (0) + +#define ADVANCE_BATCH() do { \ +} while(0) + +void +intel_batchbuffer_emit_mi_flush(struct intel_batchbuffer *batch); + +void intel_copy_bo(struct intel_batchbuffer *batch, + drm_intel_bo *dst_bo, drm_intel_bo *src_bo, + int width, int height); + +#define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) +#define i915_execbuffer2_set_context_id(eb2, context) \ + (eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK +#define i915_execbuffer2_get_context_id(eb2) \ + ((eb2).rsvd1 & I915_EXEC_CONTEXT_ID_MASK) + + +#endif diff --git a/lib/intel_chipset.h b/lib/intel_chipset.h new file mode 100755 index 00000000..9dd4c94c --- /dev/null +++ b/lib/intel_chipset.h @@ -0,0 +1,270 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#define PCI_CHIP_I810 0x7121 +#define PCI_CHIP_I810_DC100 0x7123 +#define PCI_CHIP_I810_E 0x7125 +#define PCI_CHIP_I815 0x1132 + +#define PCI_CHIP_I830_M 0x3577 +#define PCI_CHIP_845_G 0x2562 +#define PCI_CHIP_I855_GM 0x3582 +#define PCI_CHIP_I865_G 0x2572 + +#define PCI_CHIP_I915_G 0x2582 +#define PCI_CHIP_E7221_G 0x258A +#define PCI_CHIP_I915_GM 0x2592 +#define PCI_CHIP_I945_G 0x2772 +#define PCI_CHIP_I945_GM 0x27A2 +#define PCI_CHIP_I945_GME 0x27AE + +#define PCI_CHIP_Q35_G 0x29B2 +#define PCI_CHIP_G33_G 0x29C2 +#define PCI_CHIP_Q33_G 0x29D2 + +#define PCI_CHIP_IGD_GM 0xA011 +#define PCI_CHIP_IGD_G 0xA001 + +#define IS_IGDGM(devid) (devid == PCI_CHIP_IGD_GM) +#define IS_IGDG(devid) (devid == PCI_CHIP_IGD_G) +#define IS_IGD(devid) (IS_IGDG(devid) || IS_IGDGM(devid)) + +#define PCI_CHIP_I965_G 0x29A2 +#define PCI_CHIP_I965_Q 0x2992 +#define PCI_CHIP_I965_G_1 0x2982 +#define PCI_CHIP_I946_GZ 0x2972 +#define PCI_CHIP_I965_GM 0x2A02 +#define PCI_CHIP_I965_GME 0x2A12 + +#define PCI_CHIP_GM45_GM 0x2A42 + +#define PCI_CHIP_IGD_E_G 0x2E02 +#define PCI_CHIP_Q45_G 0x2E12 +#define PCI_CHIP_G45_G 0x2E22 +#define PCI_CHIP_G41_G 0x2E32 + +#define PCI_CHIP_ILD_G 0x0042 +#define PCI_CHIP_ILM_G 0x0046 + +#define PCI_CHIP_SANDYBRIDGE_GT1 0x0102 /* desktop */ +#define PCI_CHIP_SANDYBRIDGE_GT2 0x0112 +#define PCI_CHIP_SANDYBRIDGE_GT2_PLUS 0x0122 +#define PCI_CHIP_SANDYBRIDGE_M_GT1 0x0106 /* mobile */ +#define PCI_CHIP_SANDYBRIDGE_M_GT2 0x0116 +#define PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS 0x0126 +#define PCI_CHIP_SANDYBRIDGE_S 0x010A /* server */ + +#define PCI_CHIP_IVYBRIDGE_GT1 0x0152 /* desktop */ +#define PCI_CHIP_IVYBRIDGE_GT2 0x0162 +#define PCI_CHIP_IVYBRIDGE_M_GT1 0x0156 /* mobile */ +#define PCI_CHIP_IVYBRIDGE_M_GT2 0x0166 +#define PCI_CHIP_IVYBRIDGE_S 0x015a /* server */ +#define PCI_CHIP_IVYBRIDGE_S_GT2 0x016a /* server */ + +#define PCI_CHIP_HASWELL_GT1 0x0402 /* Desktop */ +#define PCI_CHIP_HASWELL_GT2 0x0412 +#define PCI_CHIP_HASWELL_GT2_PLUS 0x0422 +#define PCI_CHIP_HASWELL_M_GT1 0x0406 /* Mobile */ +#define PCI_CHIP_HASWELL_M_GT2 0x0416 +#define PCI_CHIP_HASWELL_M_GT2_PLUS 0x0426 +#define PCI_CHIP_HASWELL_S_GT1 0x040A /* Server */ +#define PCI_CHIP_HASWELL_S_GT2 0x041A +#define PCI_CHIP_HASWELL_S_GT2_PLUS 0x042A +#define PCI_CHIP_HASWELL_SDV_GT1 0x0C02 /* Desktop */ +#define PCI_CHIP_HASWELL_SDV_GT2 0x0C12 +#define PCI_CHIP_HASWELL_SDV_GT2_PLUS 0x0C22 +#define PCI_CHIP_HASWELL_SDV_M_GT1 0x0C06 /* Mobile */ +#define PCI_CHIP_HASWELL_SDV_M_GT2 0x0C16 +#define PCI_CHIP_HASWELL_SDV_M_GT2_PLUS 0x0C26 +#define PCI_CHIP_HASWELL_SDV_S_GT1 0x0C0A /* Server */ +#define PCI_CHIP_HASWELL_SDV_S_GT2 0x0C1A +#define PCI_CHIP_HASWELL_SDV_S_GT2_PLUS 0x0C2A +#define PCI_CHIP_HASWELL_ULT_GT1 0x0A02 /* Desktop */ +#define PCI_CHIP_HASWELL_ULT_GT2 0x0A12 +#define PCI_CHIP_HASWELL_ULT_GT2_PLUS 0x0A22 +#define PCI_CHIP_HASWELL_ULT_M_GT1 0x0A06 /* Mobile */ +#define PCI_CHIP_HASWELL_ULT_M_GT2 0x0A16 +#define PCI_CHIP_HASWELL_ULT_M_GT2_PLUS 0x0A26 +#define PCI_CHIP_HASWELL_ULT_S_GT1 0x0A0A /* Server */ +#define PCI_CHIP_HASWELL_ULT_S_GT2 0x0A1A +#define PCI_CHIP_HASWELL_ULT_S_GT2_PLUS 0x0A2A +#define PCI_CHIP_HASWELL_CRW_GT1 0x0D12 /* Desktop */ +#define PCI_CHIP_HASWELL_CRW_GT2 0x0D22 +#define PCI_CHIP_HASWELL_CRW_GT2_PLUS 0x0D32 +#define PCI_CHIP_HASWELL_CRW_M_GT1 0x0D16 /* Mobile */ +#define PCI_CHIP_HASWELL_CRW_M_GT2 0x0D26 +#define PCI_CHIP_HASWELL_CRW_M_GT2_PLUS 0x0D36 +#define PCI_CHIP_HASWELL_CRW_S_GT1 0x0D1A /* Server */ +#define PCI_CHIP_HASWELL_CRW_S_GT2 0x0D2A +#define PCI_CHIP_HASWELL_CRW_S_GT2_PLUS 0x0D3A + +#define PCI_CHIP_VALLEYVIEW_PO 0x0f30 /* VLV PO board */ + +#define IS_MOBILE(devid) (devid == PCI_CHIP_I855_GM || \ + devid == PCI_CHIP_I915_GM || \ + devid == PCI_CHIP_I945_GM || \ + devid == PCI_CHIP_I945_GME || \ + devid == PCI_CHIP_I965_GM || \ + devid == PCI_CHIP_I965_GME || \ + devid == PCI_CHIP_GM45_GM || IS_IGD(devid) || \ + devid == PCI_CHIP_IVYBRIDGE_M_GT1 || \ + devid == PCI_CHIP_IVYBRIDGE_M_GT2) + +#define IS_G45(devid) (devid == PCI_CHIP_IGD_E_G || \ + devid == PCI_CHIP_Q45_G || \ + devid == PCI_CHIP_G45_G || \ + devid == PCI_CHIP_G41_G) +#define IS_GM45(devid) (devid == PCI_CHIP_GM45_GM) +#define IS_G4X(devid) (IS_G45(devid) || IS_GM45(devid)) + +#define IS_ILD(devid) (devid == PCI_CHIP_ILD_G) +#define IS_ILM(devid) (devid == PCI_CHIP_ILM_G) + +#define IS_915(devid) (devid == PCI_CHIP_I915_G || \ + devid == PCI_CHIP_E7221_G || \ + devid == PCI_CHIP_I915_GM) + +#define IS_945GM(devid) (devid == PCI_CHIP_I945_GM || \ + devid == PCI_CHIP_I945_GME) + +#define IS_945(devid) (devid == PCI_CHIP_I945_G || \ + devid == PCI_CHIP_I945_GM || \ + devid == PCI_CHIP_I945_GME || \ + IS_G33(devid)) + +#define IS_G33(devid) (devid == PCI_CHIP_G33_G || \ + devid == PCI_CHIP_Q33_G || \ + devid == PCI_CHIP_Q35_G || IS_IGD(devid)) + +#define IS_GEN2(devid) (devid == PCI_CHIP_I830_M || \ + devid == PCI_CHIP_845_G || \ + devid == PCI_CHIP_I855_GM || \ + devid == PCI_CHIP_I865_G) + +#define IS_GEN3(devid) (IS_945(devid) || IS_915(devid)) + +#define IS_GEN4(devid) (devid == PCI_CHIP_I965_G || \ + devid == PCI_CHIP_I965_Q || \ + devid == PCI_CHIP_I965_G_1 || \ + devid == PCI_CHIP_I965_GM || \ + devid == PCI_CHIP_I965_GME || \ + devid == PCI_CHIP_I946_GZ || \ + IS_G4X(devid)) + +#define IS_GEN5(devid) (IS_ILD(devid) || IS_ILM(devid)) + +#define IS_GEN6(devid) (devid == PCI_CHIP_SANDYBRIDGE_GT1 || \ + devid == PCI_CHIP_SANDYBRIDGE_GT2 || \ + devid == PCI_CHIP_SANDYBRIDGE_GT2_PLUS || \ + devid == PCI_CHIP_SANDYBRIDGE_M_GT1 || \ + devid == PCI_CHIP_SANDYBRIDGE_M_GT2 || \ + devid == PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS || \ + devid == PCI_CHIP_SANDYBRIDGE_S) + +#define IS_GEN7(devid) (IS_IVYBRIDGE(devid) || \ + IS_HASWELL(devid)) + +#define IS_IVYBRIDGE(dev) (dev == PCI_CHIP_IVYBRIDGE_GT1 || \ + dev == PCI_CHIP_IVYBRIDGE_GT2 || \ + dev == PCI_CHIP_IVYBRIDGE_M_GT1 || \ + dev == PCI_CHIP_IVYBRIDGE_M_GT2 || \ + dev == PCI_CHIP_IVYBRIDGE_S || \ + dev == PCI_CHIP_IVYBRIDGE_S_GT2 || \ + dev == PCI_CHIP_VALLEYVIEW_PO) + +#define IS_VALLEYVIEW(devid) (devid == PCI_CHIP_VALLEYVIEW_PO) + +#define IS_HSW_GT1(devid) (devid == PCI_CHIP_HASWELL_GT1 || \ + devid == PCI_CHIP_HASWELL_M_GT1 || \ + devid == PCI_CHIP_HASWELL_S_GT1 || \ + devid == PCI_CHIP_HASWELL_SDV_GT1 || \ + devid == PCI_CHIP_HASWELL_SDV_M_GT1 || \ + devid == PCI_CHIP_HASWELL_SDV_S_GT1 || \ + devid == PCI_CHIP_HASWELL_ULT_GT1 || \ + devid == PCI_CHIP_HASWELL_ULT_M_GT1 || \ + devid == PCI_CHIP_HASWELL_ULT_S_GT1 || \ + devid == PCI_CHIP_HASWELL_CRW_GT1 || \ + devid == PCI_CHIP_HASWELL_CRW_M_GT1 || \ + devid == PCI_CHIP_HASWELL_CRW_S_GT1) +#define IS_HSW_GT2(devid) (devid == PCI_CHIP_HASWELL_GT2 || \ + devid == PCI_CHIP_HASWELL_M_GT2 || \ + devid == PCI_CHIP_HASWELL_S_GT2 || \ + devid == PCI_CHIP_HASWELL_SDV_GT2 || \ + devid == PCI_CHIP_HASWELL_SDV_M_GT2 || \ + devid == PCI_CHIP_HASWELL_SDV_S_GT2 || \ + devid == PCI_CHIP_HASWELL_ULT_GT2 || \ + devid == PCI_CHIP_HASWELL_ULT_M_GT2 || \ + devid == PCI_CHIP_HASWELL_ULT_S_GT2 || \ + devid == PCI_CHIP_HASWELL_CRW_GT2 || \ + devid == PCI_CHIP_HASWELL_CRW_M_GT2 || \ + devid == PCI_CHIP_HASWELL_CRW_S_GT2 || \ + devid == PCI_CHIP_HASWELL_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_M_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_S_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_SDV_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_SDV_M_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_SDV_S_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_ULT_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_ULT_M_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_ULT_S_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_CRW_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_CRW_M_GT2_PLUS || \ + devid == PCI_CHIP_HASWELL_CRW_S_GT2_PLUS) + +#define IS_HASWELL(devid) (IS_HSW_GT1(devid) || \ + IS_HSW_GT2(devid)) + +#define IS_965(devid) (IS_GEN4(devid) || \ + IS_GEN5(devid) || \ + IS_GEN6(devid) || \ + IS_GEN7(devid)) + +#define IS_INTEL(devid) (IS_GEN2(devid) || \ + IS_GEN3(devid) || \ + IS_GEN4(devid) || \ + IS_GEN5(devid) || \ + IS_GEN6(devid) || \ + IS_GEN7(devid)) + +#define HAS_PCH_SPLIT(devid) (IS_GEN5(devid) || \ + IS_GEN6(devid) || \ + IS_GEN7(devid)) + +#define HAS_BLT_RING(devid) (IS_GEN6(devid) || \ + IS_GEN7(devid)) + +#define HAS_BSD_RING(devid) (IS_GEN5(devid) || \ + IS_GEN6(devid) || \ + IS_GEN7(devid)) + +#define IS_BROADWATER(devid) (devid == PCI_CHIP_I946_GZ || \ + devid == PCI_CHIP_I965_G_1 || \ + devid == PCI_CHIP_I965_Q || \ + devid == PCI_CHIP_I965_G) + +#define IS_CRESTLINE(devid) (devid == PCI_CHIP_I965_GM || \ + devid == PCI_CHIP_I965_GME) diff --git a/lib/intel_dpio.c b/lib/intel_dpio.c new file mode 100644 index 00000000..acfd2018 --- /dev/null +++ b/lib/intel_dpio.c @@ -0,0 +1,94 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Vijay Purushothaman <vijay.a.purushothaman@intel.com> + * + */ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include "intel_gpu_tools.h" + +static uint32_t intel_display_reg_read(uint32_t reg) +{ + struct pci_device *dev = intel_get_pci_device(); + + if (IS_VALLEYVIEW(dev->device_id)) + reg += VLV_DISPLAY_BASE; + return (*(volatile uint32_t*)((volatile char*)mmio + reg)); +} + +static void intel_display_reg_write(uint32_t reg, uint32_t val) +{ + volatile uint32_t *ptr; + struct pci_device *dev = intel_get_pci_device(); + + if (IS_VALLEYVIEW(dev->device_id)) + reg += VLV_DISPLAY_BASE; + ptr = (volatile uint32_t*)((volatile char*)mmio + reg); + *ptr = val; +} + +/* + * In SoCs like Valleyview some of the PLL & Lane control registers + * can be accessed only through IO side band fabric called DPIO + */ +uint32_t +intel_dpio_reg_read(uint32_t reg) +{ + /* Check whether the side band fabric is ready to accept commands */ + do { + usleep(1); + } while (intel_display_reg_read(DPIO_PKT) & DPIO_BUSY); + + intel_display_reg_write(DPIO_REG, reg); + intel_display_reg_write(DPIO_PKT, DPIO_RID | + DPIO_OP_READ | DPIO_PORTID | DPIO_BYTE); + do { + usleep(1); + } while (intel_display_reg_read(DPIO_PKT) & DPIO_BUSY); + + return intel_display_reg_read(DPIO_DATA); +} + +/* + * In SoCs like Valleyview some of the PLL & Lane control registers + * can be accessed only through IO side band fabric called DPIO + */ +void +intel_dpio_reg_write(uint32_t reg, uint32_t val) +{ + /* Check whether the side band fabric is ready to accept commands */ + do { + usleep(1); + } while (intel_display_reg_read(DPIO_PKT) & DPIO_BUSY); + + intel_display_reg_write(DPIO_DATA, val); + intel_display_reg_write(DPIO_REG, reg); + intel_display_reg_write(DPIO_PKT, DPIO_RID | + DPIO_OP_WRITE | DPIO_PORTID | DPIO_BYTE); + do { + usleep(1); + } while (intel_display_reg_read(DPIO_PKT) & DPIO_BUSY); +} diff --git a/lib/intel_drm.c b/lib/intel_drm.c new file mode 100644 index 00000000..8d89d24f --- /dev/null +++ b/lib/intel_drm.c @@ -0,0 +1,190 @@ +/* + * Copyright © 2008 Intel Corporation + * Copyright (c) 2012, Oracle and/or its affiliates. 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include "config.h" + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <err.h> +#include <assert.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/mman.h> +#ifdef HAVE_STRUCT_SYSINFO_TOTALRAM +#include <sys/sysinfo.h> +#elif defined(HAVE_SWAPCTL) /* Solaris */ +#include <sys/swap.h> +#endif + +#include "intel_gpu_tools.h" +#include "i915_drm.h" + +uint32_t +intel_get_drm_devid(int fd) +{ + int ret; + struct drm_i915_getparam gp; + uint32_t devid; + + gp.param = I915_PARAM_CHIPSET_ID; + gp.value = (int *)&devid; + + ret = ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp)); + assert(ret == 0); + + return devid; +} + +int intel_gen(uint32_t devid) +{ + if (IS_GEN2(devid)) + return 2; + if (IS_GEN3(devid)) + return 3; + if (IS_GEN4(devid)) + return 4; + if (IS_GEN5(devid)) + return 5; + if (IS_GEN6(devid)) + return 6; + if (IS_GEN7(devid)) + return 7; + + return -1; +} + +uint64_t +intel_get_total_ram_mb(void) +{ + uint64_t retval; + +#ifdef HAVE_STRUCT_SYSINFO_TOTALRAM /* Linux */ + struct sysinfo sysinf; + int ret; + + ret = sysinfo(&sysinf); + assert(ret == 0); + + retval = sysinf.totalram; + retval *= sysinf.mem_unit; +#elif defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES) /* Solaris */ + long pagesize, npages; + + pagesize = sysconf(_SC_PAGESIZE); + npages = sysconf(_SC_PHYS_PAGES); + + retval = (uint64_t) pagesize * npages; +#else +#error "Unknown how to get RAM size for this OS" +#endif + + return retval / (1024*1024); +} + +uint64_t +intel_get_total_swap_mb(void) +{ + uint64_t retval; + +#ifdef HAVE_STRUCT_SYSINFO_TOTALRAM /* Linux */ + struct sysinfo sysinf; + int ret; + + ret = sysinfo(&sysinf); + assert(ret == 0); + + retval = sysinf.totalswap; + retval *= sysinf.mem_unit; +#elif defined(HAVE_SWAPCTL) /* Solaris */ + long pagesize = sysconf(_SC_PAGESIZE); + uint64_t totalpages = 0; + swaptbl_t *swt; + char *buf; + int n, i; + + if ((n = swapctl(SC_GETNSWP, NULL)) == -1) { + perror("swapctl: GETNSWP"); + return 0; + } + if (n == 0) { + /* no error, but no swap devices either */ + return 0; + } + + swt = malloc(sizeof(struct swaptable) + (n * sizeof(swapent_t))); + buf = malloc(n * MAXPATHLEN); + if (!swt || !buf) { + perror("malloc"); + } else { + swt->swt_n = n; + for (i = 0 ; i < n; i++) { + swt->swt_ent[i].ste_path = buf + (i * MAXPATHLEN); + } + + if ((n = swapctl(SC_LIST, swt)) == -1) { + perror("swapctl: LIST"); + } else { + for (i = 0; i < swt->swt_n; i++) { + totalpages += swt->swt_ent[i].ste_pages; + } + } + } + free(swt); + free(buf); + + retval = (uint64_t) pagesize * totalpages; +#else +#warning "Unknown how to get swap size for this OS" + return 0; +#endif + + return retval / (1024*1024); +} + + +/* + * When testing a port to a new platform, create a standalone test binary + * by running: + * cc -o porttest intel_drm.c -I.. -DSTANDALONE_TEST `pkg-config --cflags libdrm` + * and then running the resulting porttest program. + */ +#ifdef STANDALONE_TEST +void *mmio; + +int main(int argc, char **argv) +{ + printf("Total RAM: %" PRIu64 " Mb\n", intel_get_total_ram_mb()); + printf("Total Swap: %" PRIu64 " Mb\n", intel_get_total_swap_mb()); + + return 0; +} +#endif /* STANDALONE_TEST */ diff --git a/lib/intel_gpu_tools.h b/lib/intel_gpu_tools.h new file mode 100644 index 00000000..245d1de8 --- /dev/null +++ b/lib/intel_gpu_tools.h @@ -0,0 +1,104 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifndef INTEL_GPU_TOOLS_H +#define INTEL_GPU_TOOLS_H + +#include <stdint.h> +#include <sys/types.h> +#include <pciaccess.h> + +#include "intel_chipset.h" +#include "intel_reg.h" + +#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) + +extern void *mmio; +void intel_get_mmio(struct pci_device *pci_dev); + +/* New style register access API */ +int intel_register_access_init(struct pci_device *pci_dev, int safe); +void intel_register_access_fini(void); +uint32_t intel_register_read(uint32_t reg); +void intel_register_write(uint32_t reg, uint32_t val); +/* Following functions are relevant only for SoCs like Valleyview */ +uint32_t intel_dpio_reg_read(uint32_t reg); +void intel_dpio_reg_write(uint32_t reg, uint32_t val); + +#define INTEL_RANGE_RSVD (0<<0) /* Shouldn't be read or written */ +#define INTEL_RANGE_READ (1<<0) +#define INTEL_RANGE_WRITE (1<<1) +#define INTEL_RANGE_RW (INTEL_RANGE_READ | INTEL_RANGE_WRITE) +#define INTEL_RANGE_END (1<<31) + +struct intel_register_range { + uint32_t base; + uint32_t size; + uint32_t flags; +}; + +struct intel_register_map { + struct intel_register_range *map; + uint32_t top; + uint32_t alignment_mask; +}; +struct intel_register_map intel_get_register_map(uint32_t devid); +struct intel_register_range *intel_get_register_range(struct intel_register_map map, uint32_t offset, int mode); + + +static inline uint32_t +INREG(uint32_t reg) +{ + return *(volatile uint32_t *)((volatile char *)mmio + reg); +} + +static inline void +OUTREG(uint32_t reg, uint32_t val) +{ + *(volatile uint32_t *)((volatile char *)mmio + reg) = val; +} + +struct pci_device *intel_get_pci_device(void); + +uint32_t intel_get_drm_devid(int fd); +int intel_gen(uint32_t devid); +uint64_t intel_get_total_ram_mb(void); +uint64_t intel_get_total_swap_mb(void); + +void intel_map_file(char *); + +enum pch_type { + PCH_IBX, + PCH_CPT, +}; + +extern enum pch_type pch; +void intel_check_pch(void); + +#define HAS_CPT (pch == PCH_CPT) + +#endif /* INTEL_GPU_TOOLS_H */ diff --git a/lib/intel_mmio.c b/lib/intel_mmio.c new file mode 100644 index 00000000..ecb049b7 --- /dev/null +++ b/lib/intel_mmio.c @@ -0,0 +1,264 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Ben Widawsky <ben@bwidawsk.net> + * + */ + +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <errno.h> +#include <err.h> +#include <assert.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include "intel_gpu_tools.h" + +void *mmio; + +static struct _mmio_data { + int inited; + bool safe; + char debugfs_path[FILENAME_MAX]; + char debugfs_forcewake_path[FILENAME_MAX]; + uint32_t i915_devid; + struct intel_register_map map; + int key; +} mmio_data; + +void +intel_map_file(char *file) +{ + int fd; + struct stat st; + + fd = open(file, O_RDWR); + if (fd == -1) { + fprintf(stderr, "Couldn't open %s: %s\n", file, + strerror(errno)); + exit(1); + } + fstat(fd, &st); + mmio = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (mmio == MAP_FAILED) { + fprintf(stderr, "Couldn't mmap %s: %s\n", file, + strerror(errno)); + exit(1); + } + close(fd); +} + +void +intel_get_mmio(struct pci_device *pci_dev) +{ + uint32_t devid, gen; + int mmio_bar, mmio_size; + int error; + + devid = pci_dev->device_id; + if (IS_GEN2(devid)) + mmio_bar = 1; + else + mmio_bar = 0; + + gen = intel_gen(devid); + if (gen < 3) + mmio_size = 64*1024; + else if (gen < 5) + mmio_size = 512*1024; + else + mmio_size = 2*1024*1024; + + error = pci_device_map_range (pci_dev, + pci_dev->regions[mmio_bar].base_addr, + mmio_size, + PCI_DEV_MAP_FLAG_WRITABLE, + &mmio); + + if (error != 0) { + fprintf(stderr, "Couldn't map MMIO region: %s\n", + strerror(error)); + exit(1); + } +} + +/* + * If successful, i915_debugfs_path and i915_debugfs_forcewake_path are both + * updated with the correct path. + */ +static int +find_debugfs_path(const char *dri_base) +{ + char buf[FILENAME_MAX]; + struct stat sb; + int i, ret; + + for (i = 0; i < 16; i++) { + snprintf(buf, FILENAME_MAX, "%s/%i/name", dri_base, i); + + snprintf(mmio_data.debugfs_path, FILENAME_MAX, + "%s/%i/", dri_base, i); + snprintf(mmio_data.debugfs_forcewake_path, FILENAME_MAX, + "%s/%i/i915_forcewake_user", dri_base, i); + + ret = stat(mmio_data.debugfs_forcewake_path, &sb); + if (ret) { + mmio_data.debugfs_path[0] = 0; + mmio_data.debugfs_forcewake_path[0] = 0; + } else + return 0; + } + + return -1; +} + +static int +get_forcewake_lock(void) +{ + return open(mmio_data.debugfs_forcewake_path, 0); +} + +static void +release_forcewake_lock(int fd) +{ + close(fd); +} + +/* + * Initialize register access library. + * + * @pci_dev: pci device we're mucking with + * @safe: use safe register access tables + */ +int +intel_register_access_init(struct pci_device *pci_dev, int safe) +{ + int ret; + + /* after old API is deprecated, remove this */ + if (mmio == NULL) + intel_get_mmio(pci_dev); + + assert(mmio != NULL); + + if (mmio_data.inited) + return -1; + + mmio_data.safe = safe != 0 ? true : false; + mmio_data.i915_devid = pci_dev->device_id; + if (mmio_data.safe) + mmio_data.map = intel_get_register_map(mmio_data.i915_devid); + + if (!(IS_GEN6(pci_dev->device_id) || + IS_GEN7(pci_dev->device_id))) + goto done; + + /* Find where the forcewake lock is */ + ret = find_debugfs_path("/sys/kernel/debug/dri"); + if (ret) { + ret = find_debugfs_path("/debug/dri"); + if (ret) { + fprintf(stderr, "Couldn't find path to dri/debugfs entry\n"); + return ret; + } + } + mmio_data.key = get_forcewake_lock(); + +done: + mmio_data.inited++; + return 0; +} + +void +intel_register_access_fini(void) +{ + if (mmio_data.key) + release_forcewake_lock(mmio_data.key); + mmio_data.inited--; +} + +uint32_t +intel_register_read(uint32_t reg) +{ + struct intel_register_range *range; + uint32_t ret; + + assert(mmio_data.inited); + + if (intel_gen(mmio_data.i915_devid) >= 6) + assert(mmio_data.key != -1); + + if (!mmio_data.safe) + goto read_out; + + range = intel_get_register_range(mmio_data.map, + reg, + INTEL_RANGE_READ); + + if(!range) { + fprintf(stderr, "Register read blocked for safety " + "(*0x%08x)\n", reg); + ret = 0xffffffff; + goto out; + } + +read_out: + ret = *(volatile uint32_t *)((volatile char *)mmio + reg); +out: + return ret; +} + +void +intel_register_write(uint32_t reg, uint32_t val) +{ + struct intel_register_range *range; + + assert(mmio_data.inited); + + if (intel_gen(mmio_data.i915_devid) >= 6) + assert(mmio_data.key != -1); + + if (!mmio_data.safe) + goto write_out; + + range = intel_get_register_range(mmio_data.map, + reg, + INTEL_RANGE_WRITE); + + if (!range) { + fprintf(stderr, "Register write blocked for safety " + "(*0x%08x = 0x%x)\n", reg, val); + } + +write_out: + *(volatile uint32_t *)((volatile char *)mmio + reg) = val; +} diff --git a/lib/intel_pci.c b/lib/intel_pci.c new file mode 100644 index 00000000..7228daec --- /dev/null +++ b/lib/intel_pci.c @@ -0,0 +1,89 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <err.h> +#include <assert.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include "intel_gpu_tools.h" + +enum pch_type pch; + +struct pci_device * +intel_get_pci_device(void) +{ + struct pci_device *pci_dev; + int error; + + error = pci_system_init(); + if (error != 0) { + fprintf(stderr, "Couldn't initialize PCI system: %s\n", + strerror(error)); + exit(1); + } + + /* Grab the graphics card */ + pci_dev = pci_device_find_by_slot(0, 0, 2, 0); + if (pci_dev == NULL) + errx(1, "Couldn't find graphics card"); + + error = pci_device_probe(pci_dev); + if (error != 0) { + fprintf(stderr, "Couldn't probe graphics card: %s\n", + strerror(error)); + exit(1); + } + + if (pci_dev->vendor_id != 0x8086) + errx(1, "Graphics card is non-intel"); + + return pci_dev; +} + +void +intel_check_pch(void) +{ + struct pci_device *pch_dev; + + pch_dev = pci_device_find_by_slot(0, 0, 31, 0); + if (pch_dev == NULL) + return; + + if (pch_dev->vendor_id == 0x8086 && + (((pch_dev->device_id & 0xff00) == 0x1c00) || + (pch_dev->device_id & 0xff00) == 0x1e00)) + pch = PCH_CPT; +} + diff --git a/lib/intel_reg.h b/lib/intel_reg.h new file mode 100644 index 00000000..ae220b83 --- /dev/null +++ b/lib/intel_reg.h @@ -0,0 +1,3758 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_reg.h,v 1.13 2003/02/06 04:18:04 dawes Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +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 PRECISION INSIGHT 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. + +**************************************************************************/ + +/** @file + * Register names and fields for Intel graphics. + */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Eric Anholt <eric@anholt.net> + * + * based on the i740 driver by + * Kevin E. Martin <kevin@precisioninsight.com> + * + * + */ + +#ifndef _I810_REG_H +#define _I810_REG_H + +/* I/O register offsets + */ +#define SRX 0x3C4 /* p208 */ +#define GRX 0x3CE /* p213 */ +#define ARX 0x3C0 /* p224 */ + +/* VGA Color Palette Registers */ +#define DACMASK 0x3C6 /* p232 */ +#define DACSTATE 0x3C7 /* p232 */ +#define DACRX 0x3C7 /* p233 */ +#define DACWX 0x3C8 /* p233 */ +#define DACDATA 0x3C9 /* p233 */ + +/* CRT Controller Registers (CRX) */ +#define START_ADDR_HI 0x0C /* p246 */ +#define START_ADDR_LO 0x0D /* p247 */ +#define VERT_SYNC_END 0x11 /* p249 */ +#define EXT_VERT_TOTAL 0x30 /* p257 */ +#define EXT_VERT_DISPLAY 0x31 /* p258 */ +#define EXT_VERT_SYNC_START 0x32 /* p259 */ +#define EXT_VERT_BLANK_START 0x33 /* p260 */ +#define EXT_HORIZ_TOTAL 0x35 /* p261 */ +#define EXT_HORIZ_BLANK 0x39 /* p261 */ +#define EXT_START_ADDR 0x40 /* p262 */ +#define EXT_START_ADDR_ENABLE 0x80 +#define EXT_OFFSET 0x41 /* p263 */ +#define EXT_START_ADDR_HI 0x42 /* p263 */ +#define INTERLACE_CNTL 0x70 /* p264 */ +#define INTERLACE_ENABLE 0x80 +#define INTERLACE_DISABLE 0x00 + +/* Miscellaneous Output Register + */ +#define MSR_R 0x3CC /* p207 */ +#define MSR_W 0x3C2 /* p207 */ +#define IO_ADDR_SELECT 0x01 + +#define MDA_BASE 0x3B0 /* p207 */ +#define CGA_BASE 0x3D0 /* p207 */ + +/* CR80 - IO Control, p264 + */ +#define IO_CTNL 0x80 +#define EXTENDED_ATTR_CNTL 0x02 +#define EXTENDED_CRTC_CNTL 0x01 + +/* GR10 - Address mapping, p221 + */ +#define ADDRESS_MAPPING 0x10 +#define PAGE_TO_LOCAL_MEM_ENABLE 0x10 +#define GTT_MEM_MAP_ENABLE 0x08 +#define PACKED_MODE_ENABLE 0x04 +#define LINEAR_MODE_ENABLE 0x02 +#define PAGE_MAPPING_ENABLE 0x01 + +#define HOTKEY_VBIOS_SWITCH_BLOCK 0x80 +#define HOTKEY_SWITCH 0x20 +#define HOTKEY_TOGGLE 0x10 + +/* Blitter control, p378 + */ +#define BITBLT_CNTL 0x7000c +#define COLEXP_MODE 0x30 +#define COLEXP_8BPP 0x00 +#define COLEXP_16BPP 0x10 +#define COLEXP_24BPP 0x20 +#define COLEXP_RESERVED 0x30 +#define BITBLT_STATUS 0x01 + +#define CHDECMISC 0x10111 +#define DCC 0x10200 +#define C0DRB0 0x10200 +#define C0DRB1 0x10202 +#define C0DRB2 0x10204 +#define C0DRB3 0x10206 +#define C0DRA01 0x10208 +#define C0DRA23 0x1020a +#define C1DRB0 0x10600 +#define C1DRB1 0x10602 +#define C1DRB2 0x10604 +#define C1DRB3 0x10606 +#define C1DRA01 0x10608 +#define C1DRA23 0x1060a + +/* p375. + */ +#define DISPLAY_CNTL 0x70008 +#define VGA_WRAP_MODE 0x02 +#define VGA_WRAP_AT_256KB 0x00 +#define VGA_NO_WRAP 0x02 +#define GUI_MODE 0x01 +#define STANDARD_VGA_MODE 0x00 +#define HIRES_MODE 0x01 + +/* p375 + */ +#define PIXPIPE_CONFIG_0 0x70009 +#define DAC_8_BIT 0x80 +#define DAC_6_BIT 0x00 +#define HW_CURSOR_ENABLE 0x10 +#define EXTENDED_PALETTE 0x01 + +/* p375 + */ +#define PIXPIPE_CONFIG_1 0x7000a +#define DISPLAY_COLOR_MODE 0x0F +#define DISPLAY_VGA_MODE 0x00 +#define DISPLAY_8BPP_MODE 0x02 +#define DISPLAY_15BPP_MODE 0x04 +#define DISPLAY_16BPP_MODE 0x05 +#define DISPLAY_24BPP_MODE 0x06 +#define DISPLAY_32BPP_MODE 0x07 + +/* p375 + */ +#define PIXPIPE_CONFIG_2 0x7000b +#define DISPLAY_GAMMA_ENABLE 0x08 +#define DISPLAY_GAMMA_DISABLE 0x00 +#define OVERLAY_GAMMA_ENABLE 0x04 +#define OVERLAY_GAMMA_DISABLE 0x00 + + +/* p380 + */ +#define DISPLAY_BASE 0x70020 +#define DISPLAY_BASE_MASK 0x03fffffc + + +/* Cursor control registers, pp383-384 + */ +/* Desktop (845G, 865G) */ +#define CURSOR_CONTROL 0x70080 +#define CURSOR_ENABLE 0x80000000 +#define CURSOR_GAMMA_ENABLE 0x40000000 +#define CURSOR_STRIDE_MASK 0x30000000 +#define CURSOR_FORMAT_SHIFT 24 +#define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_3C (0x01 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_4C (0x02 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_ARGB (0x04 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_XRGB (0x05 << CURSOR_FORMAT_SHIFT) + +/* Mobile and i810 */ +#define CURSOR_A_CONTROL CURSOR_CONTROL +#define CURSOR_ORIGIN_SCREEN 0x00 /* i810 only */ +#define CURSOR_ORIGIN_DISPLAY 0x1 /* i810 only */ +#define CURSOR_MODE 0x27 +#define CURSOR_MODE_DISABLE 0x00 +#define CURSOR_MODE_32_4C_AX 0x01 /* i810 only */ +#define CURSOR_MODE_64_3C 0x04 +#define CURSOR_MODE_64_4C_AX 0x05 +#define CURSOR_MODE_64_4C 0x06 +#define CURSOR_MODE_64_32B_AX 0x07 +#define CURSOR_MODE_64_ARGB_AX (0x20 | CURSOR_MODE_64_32B_AX) +#define MCURSOR_PIPE_SELECT (1 << 28) +#define MCURSOR_PIPE_A 0x00 +#define MCURSOR_PIPE_B (1 << 28) +#define MCURSOR_GAMMA_ENABLE (1 << 26) +#define MCURSOR_MEM_TYPE_LOCAL (1 << 25) + + +#define CURSOR_BASEADDR 0x70084 +#define CURSOR_A_BASE CURSOR_BASEADDR +#define CURSOR_BASEADDR_MASK 0x1FFFFF00 +#define CURSOR_A_POSITION 0x70088 +#define CURSOR_POS_SIGN 0x8000 +#define CURSOR_POS_MASK 0x007FF +#define CURSOR_X_SHIFT 0 +#define CURSOR_Y_SHIFT 16 +#define CURSOR_X_LO 0x70088 +#define CURSOR_X_HI 0x70089 +#define CURSOR_X_POS 0x00 +#define CURSOR_X_NEG 0x80 +#define CURSOR_Y_LO 0x7008A +#define CURSOR_Y_HI 0x7008B +#define CURSOR_Y_POS 0x00 +#define CURSOR_Y_NEG 0x80 + +#define CURSOR_A_PALETTE0 0x70090 +#define CURSOR_A_PALETTE1 0x70094 +#define CURSOR_A_PALETTE2 0x70098 +#define CURSOR_A_PALETTE3 0x7009C + +#define CURSOR_SIZE 0x700A0 +#define CURSOR_SIZE_MASK 0x3FF +#define CURSOR_SIZE_HSHIFT 0 +#define CURSOR_SIZE_VSHIFT 12 + +#define CURSOR_B_CONTROL 0x700C0 +#define CURSOR_B_BASE 0x700C4 +#define CURSOR_B_POSITION 0x700C8 +#define CURSOR_B_PALETTE0 0x700D0 +#define CURSOR_B_PALETTE1 0x700D4 +#define CURSOR_B_PALETTE2 0x700D8 +#define CURSOR_B_PALETTE3 0x700DC + + +/* Similar registers exist in Device 0 on the i810 (pp55-65), but I'm + * not sure they refer to local (graphics) memory. + * + * These details are for the local memory control registers, + * (pp301-310). The test machines are not equiped with local memory, + * so nothing is tested. Only a single row seems to be supported. + */ +#define DRAM_ROW_TYPE 0x3000 +#define DRAM_ROW_0 0x01 +#define DRAM_ROW_0_SDRAM 0x01 +#define DRAM_ROW_0_EMPTY 0x00 +#define DRAM_ROW_CNTL_LO 0x3001 +#define DRAM_PAGE_MODE_CTRL 0x10 +#define DRAM_RAS_TO_CAS_OVRIDE 0x08 +#define DRAM_CAS_LATENCY 0x04 +#define DRAM_RAS_TIMING 0x02 +#define DRAM_RAS_PRECHARGE 0x01 +#define DRAM_ROW_CNTL_HI 0x3002 +#define DRAM_REFRESH_RATE 0x18 +#define DRAM_REFRESH_DISABLE 0x00 +#define DRAM_REFRESH_60HZ 0x08 +#define DRAM_REFRESH_FAST_TEST 0x10 +#define DRAM_REFRESH_RESERVED 0x18 +#define DRAM_SMS 0x07 +#define DRAM_SMS_NORMAL 0x00 +#define DRAM_SMS_NOP_ENABLE 0x01 +#define DRAM_SMS_ABPCE 0x02 +#define DRAM_SMS_MRCE 0x03 +#define DRAM_SMS_CBRCE 0x04 + +/* p307 + */ +#define DPMS_SYNC_SELECT 0x5002 +#define VSYNC_CNTL 0x08 +#define VSYNC_ON 0x00 +#define VSYNC_OFF 0x08 +#define HSYNC_CNTL 0x02 +#define HSYNC_ON 0x00 +#define HSYNC_OFF 0x02 + +#define GPIOA 0x5010 +#define GPIOB 0x5014 +#define GPIOC 0x5018 +#define GPIOD 0x501c +#define GPIOE 0x5020 +#define GPIOF 0x5024 +#define GPIOG 0x5028 +#define GPIOH 0x502c +# define GPIO_CLOCK_DIR_MASK (1 << 0) +# define GPIO_CLOCK_DIR_IN (0 << 1) +# define GPIO_CLOCK_DIR_OUT (1 << 1) +# define GPIO_CLOCK_VAL_MASK (1 << 2) +# define GPIO_CLOCK_VAL_OUT (1 << 3) +# define GPIO_CLOCK_VAL_IN (1 << 4) +# define GPIO_CLOCK_PULLUP_DISABLE (1 << 5) +# define GPIO_DATA_DIR_MASK (1 << 8) +# define GPIO_DATA_DIR_IN (0 << 9) +# define GPIO_DATA_DIR_OUT (1 << 9) +# define GPIO_DATA_VAL_MASK (1 << 10) +# define GPIO_DATA_VAL_OUT (1 << 11) +# define GPIO_DATA_VAL_IN (1 << 12) +# define GPIO_DATA_PULLUP_DISABLE (1 << 13) + +/* GMBus registers for hardware-assisted (non-bitbanging) I2C access */ +#define GMBUS0 0x5100 +#define GMBUS1 0x5104 +#define GMBUS2 0x5108 +#define GMBUS3 0x510c +#define GMBUS4 0x5110 +#define GMBUS5 0x5120 + +/* p317, 319 + */ +#define VCLK2_VCO_M 0x6008 /* treat as 16 bit? (includes msbs) */ +#define VCLK2_VCO_N 0x600a +#define VCLK2_VCO_DIV_SEL 0x6012 + +#define VCLK_DIVISOR_VGA0 0x6000 +#define VCLK_DIVISOR_VGA1 0x6004 +#define VCLK_POST_DIV 0x6010 +/** Selects a post divisor of 4 instead of 2. */ +# define VGA1_PD_P2_DIV_4 (1 << 15) +/** Overrides the p2 post divisor field */ +# define VGA1_PD_P1_DIV_2 (1 << 13) +# define VGA1_PD_P1_SHIFT 8 +/** P1 value is 2 greater than this field */ +# define VGA1_PD_P1_MASK (0x1f << 8) +/** Selects a post divisor of 4 instead of 2. */ +# define VGA0_PD_P2_DIV_4 (1 << 7) +/** Overrides the p2 post divisor field */ +# define VGA0_PD_P1_DIV_2 (1 << 5) +# define VGA0_PD_P1_SHIFT 0 +/** P1 value is 2 greater than this field */ +# define VGA0_PD_P1_MASK (0x1f << 0) + +#define POST_DIV_SELECT 0x70 +#define POST_DIV_1 0x00 +#define POST_DIV_2 0x10 +#define POST_DIV_4 0x20 +#define POST_DIV_8 0x30 +#define POST_DIV_16 0x40 +#define POST_DIV_32 0x50 +#define VCO_LOOP_DIV_BY_4M 0x00 +#define VCO_LOOP_DIV_BY_16M 0x04 + + +/* Instruction Parser Mode Register + * - p281 + * - 2 new bits. + */ +#define INST_PM 0x20c0 +#define AGP_SYNC_PACKET_FLUSH_ENABLE 0x20 /* reserved */ +#define SYNC_PACKET_FLUSH_ENABLE 0x10 +#define TWO_D_INST_DISABLE 0x08 +#define THREE_D_INST_DISABLE 0x04 +#define STATE_VAR_UPDATE_DISABLE 0x02 +#define PAL_STIP_DISABLE 0x01 +#define GEN6_GLOBAL_DEBUG_ENABLE 0x10 + + +#define MEMMODE 0x20dc + + +/* Instruction parser error register. p279 + */ +#define IPEIR 0x2088 +#define IPEHR 0x208C + +#define INST_DONE 0x2090 +# define IDCT_DONE (1 << 30) +# define IQ_DONE (1 << 29) +# define PR_DONE (1 << 28) +# define VLD_DONE (1 << 27) +# define IP_DONE (1 << 26) +# define FBC_DONE (1 << 25) +# define BINNER_DONE (1 << 24) +# define SF_DONE (1 << 23) +# define SE_DONE (1 << 22) +# define WM_DONE (1 << 21) +# define IZ_DONE (1 << 20) +# define PERSPECTIVE_INTERP_DONE (1 << 19) +# define DISPATCHER_DONE (1 << 18) +# define PROJECTION_DONE (1 << 17) +# define DEPENDENT_ADDRESS_DONE (1 << 16) +# define QUAD_CACHE_DONE (1 << 15) +# define TEXTURE_FETCH_DONE (1 << 14) +# define TEXTURE_DECOMPRESS_DONE (1 << 13) +# define SAMPLER_CACHE_DONE (1 << 12) +# define FILTER_DONE (1 << 11) +# define BYPASS_FIFO_DONE (1 << 10) +# define PS_DONE (1 << 9) +# define CC_DONE (1 << 8) +# define MAP_FILTER_DONE (1 << 7) +# define MAP_L2_IDLE (1 << 6) +# define RING_2_ENABLE (1 << 2) +# define RING_1_ENABLE (1 << 1) +# define RING_0_ENABLE (1 << 0) + +# define I830_GMBUS_DONE (1 << 26) +# define I830_FBC_DONE (1 << 25) +# define I830_BINNER_DONE (1 << 24) +# define I830_MPEG_DONE (1 << 23) +# define I830_MECO_DONE (1 << 22) +# define I830_MCD_DONE (1 << 21) +# define I830_MCSTP_DONE (1 << 20) +# define I830_CC_DONE (1 << 19) +# define I830_DG_DONE (1 << 18) +# define I830_DCMP_DONE (1 << 17) +# define I830_FTCH_DONE (1 << 16) +# define I830_IT_DONE (1 << 15) +# define I830_MG_DONE (1 << 14) +# define I830_MEC_DONE (1 << 13) +# define I830_PC_DONE (1 << 12) +# define I830_QCC_DONE (1 << 11) +# define I830_TB_DONE (1 << 10) +# define I830_WM_DONE (1 << 9) +# define I830_EF_DONE (1 << 8) +# define I830_BLITTER_DONE (1 << 7) +# define I830_MAP_L2_DONE (1 << 6) +# define I830_SECONDARY_RING_3_DONE (1 << 5) +# define I830_SECONDARY_RING_2_DONE (1 << 4) +# define I830_SECONDARY_RING_1_DONE (1 << 3) +# define I830_SECONDARY_RING_0_DONE (1 << 2) +# define I830_PRIMARY_RING_1_DONE (1 << 1) +# define I830_PRIMARY_RING_0_DONE (1 << 0) + +#define NOP_ID 0x2094 + +#define SCPD0 0x209c /* debug */ +#define INST_PS 0x20c4 +#define IPEIR_I965 0x2064 /* i965 */ +#define IPEHR_I965 0x2068 /* i965 */ +#define INST_DONE_I965 0x206c +# define I965_ROW_0_EU_0_DONE (1 << 31) +# define I965_ROW_0_EU_1_DONE (1 << 30) +# define I965_ROW_0_EU_2_DONE (1 << 29) +# define I965_ROW_0_EU_3_DONE (1 << 28) +# define I965_ROW_1_EU_0_DONE (1 << 27) +# define I965_ROW_1_EU_1_DONE (1 << 26) +# define I965_ROW_1_EU_2_DONE (1 << 25) +# define I965_ROW_1_EU_3_DONE (1 << 24) +# define I965_SF_DONE (1 << 23) +# define I965_SE_DONE (1 << 22) +# define I965_WM_DONE (1 << 21) +# define I965_DISPATCHER_DONE (1 << 18) +# define I965_PROJECTION_DONE (1 << 17) +# define I965_DG_DONE (1 << 16) +# define I965_QUAD_CACHE_DONE (1 << 15) +# define I965_TEXTURE_FETCH_DONE (1 << 14) +# define I965_TEXTURE_DECOMPRESS_DONE (1 << 13) +# define I965_SAMPLER_CACHE_DONE (1 << 12) +# define I965_FILTER_DONE (1 << 11) +# define I965_BYPASS_DONE (1 << 10) +# define I965_PS_DONE (1 << 9) +# define I965_CC_DONE (1 << 8) +# define I965_MAP_FILTER_DONE (1 << 7) +# define I965_MAP_L2_IDLE (1 << 6) +# define I965_MA_ROW_0_DONE (1 << 5) +# define I965_MA_ROW_1_DONE (1 << 4) +# define I965_IC_ROW_0_DONE (1 << 3) +# define I965_IC_ROW_1_DONE (1 << 2) +# define I965_CP_DONE (1 << 1) +# define I965_RING_0_ENABLE (1 << 0) + +# define ILK_ROW_0_EU_0_DONE (1 << 31) +# define ILK_ROW_0_EU_1_DONE (1 << 30) +# define ILK_ROW_0_EU_2_DONE (1 << 29) +# define ILK_ROW_0_EU_3_DONE (1 << 28) +# define ILK_ROW_1_EU_0_DONE (1 << 27) +# define ILK_ROW_1_EU_1_DONE (1 << 26) +# define ILK_ROW_1_EU_2_DONE (1 << 25) +# define ILK_ROW_1_EU_3_DONE (1 << 24) +# define ILK_ROW_2_EU_0_DONE (1 << 23) +# define ILK_ROW_2_EU_1_DONE (1 << 22) +# define ILK_ROW_2_EU_2_DONE (1 << 21) +# define ILK_ROW_2_EU_3_DONE (1 << 20) +# define ILK_VCP_DONE (1 << 19) +# define ILK_ROW_0_MATH_DONE (1 << 18) +# define ILK_ROW_1_MATH_DONE (1 << 17) +# define ILK_ROW_2_MATH_DONE (1 << 16) +# define ILK_VC1_DONE (1 << 15) +# define ILK_ROW_0_MA_DONE (1 << 14) +# define ILK_ROW_1_MA_DONE (1 << 13) +# define ILK_ROW_2_MA_DONE (1 << 12) +# define ILK_ROW_0_ISC_DONE (1 << 11) +# define ILK_ROW_1_ISC_DONE (1 << 10) +# define ILK_ROW_2_ISC_DONE (1 << 9) +# define ILK_VFE_DONE (1 << 8) +# define ILK_TD_DONE (1 << 7) +# define ILK_SVTS_DONE (1 << 6) +# define ILK_TS_DONE (1 << 5) +# define ILK_GW_DONE (1 << 4) +# define ILK_AI_DONE (1 << 3) +# define ILK_AC_DONE (1 << 2) +# define ILK_AM_DONE (1 << 1) + +#define GEN6_INSTDONE_1 0x206c +# define GEN6_MA_3_DONE (1 << 31) +# define GEN6_EU_32_DONE (1 << 30) +# define GEN6_EU_31_DONE (1 << 29) +# define GEN6_EU_30_DONE (1 << 28) +# define GEN6_MA_2_DONE (1 << 27) +# define GEN6_EU_22_DONE (1 << 26) +# define GEN6_EU_21_DONE (1 << 25) +# define GEN6_EU_20_DONE (1 << 24) +# define GEN6_MA_1_DONE (1 << 23) +# define GEN6_EU_12_DONE (1 << 22) +# define GEN6_EU_11_DONE (1 << 21) +# define GEN6_EU_10_DONE (1 << 20) +# define GEN6_MA_0_DONE (1 << 19) +# define GEN6_EU_02_DONE (1 << 18) +# define GEN6_EU_01_DONE (1 << 17) +# define GEN6_EU_00_DONE (1 << 16) +# define GEN6_IC_3_DONE (1 << 15) +# define GEN6_IC_2_DONE (1 << 14) +# define GEN6_IC_1_DONE (1 << 13) +# define GEN6_IC_0_DONE (1 << 12) +# define GEN6_ISC_10_DONE (1 << 11) +# define GEN6_ISC_32_DONE (1 << 10) +# define GEN6_VSC_DONE (1 << 9) +# define GEN6_IEF_DONE (1 << 8) +# define GEN6_VFE_DONE (1 << 7) +# define GEN6_TD_DONE (1 << 6) +# define GEN6_TS_DONE (1 << 4) +# define GEN6_GW_DONE (1 << 3) +# define GEN6_HIZ_DONE (1 << 2) +# define GEN6_AVS_DONE (1 << 1) + +#define INST_PS_I965 0x2070 + +/* Current active ring head address: + */ +#define ACTHD_I965 0x2074 +#define ACTHD 0x20C8 + +/* Current primary/secondary DMA fetch addresses: + */ +#define DMA_FADD_P 0x2078 +#define DMA_FADD_S 0x20d4 +#define INST_DONE_1 0x207c +# define I965_GW_CS_DONE_CR (1 << 19) +# define I965_SVSM_CS_DONE_CR (1 << 18) +# define I965_SVDW_CS_DONE_CR (1 << 17) +# define I965_SVDR_CS_DONE_CR (1 << 16) +# define I965_SVRW_CS_DONE_CR (1 << 15) +# define I965_SVRR_CS_DONE_CR (1 << 14) +# define I965_SVTW_CS_DONE_CR (1 << 13) +# define I965_MASM_CS_DONE_CR (1 << 12) +# define I965_MASF_CS_DONE_CR (1 << 11) +# define I965_MAW_CS_DONE_CR (1 << 10) +# define I965_EM1_CS_DONE_CR (1 << 9) +# define I965_EM0_CS_DONE_CR (1 << 8) +# define I965_UC1_CS_DONE (1 << 7) +# define I965_UC0_CS_DONE (1 << 6) +# define I965_URB_CS_DONE (1 << 5) +# define I965_ISC_CS_DONE (1 << 4) +# define I965_CL_CS_DONE (1 << 3) +# define I965_GS_CS_DONE (1 << 2) +# define I965_VS0_CS_DONE (1 << 1) +# define I965_VF_CS_DONE (1 << 0) + +# define G4X_BCS_DONE (1 << 31) +# define G4X_CS_DONE (1 << 30) +# define G4X_MASF_DONE (1 << 29) +# define G4X_SVDW_DONE (1 << 28) +# define G4X_SVDR_DONE (1 << 27) +# define G4X_SVRW_DONE (1 << 26) +# define G4X_SVRR_DONE (1 << 25) +# define G4X_ISC_DONE (1 << 24) +# define G4X_MT_DONE (1 << 23) +# define G4X_RC_DONE (1 << 22) +# define G4X_DAP_DONE (1 << 21) +# define G4X_MAWB_DONE (1 << 20) +# define G4X_MT_IDLE (1 << 19) +# define G4X_GBLT_BUSY (1 << 18) +# define G4X_SVSM_DONE (1 << 17) +# define G4X_MASM_DONE (1 << 16) +# define G4X_QC_DONE (1 << 15) +# define G4X_FL_DONE (1 << 14) +# define G4X_SC_DONE (1 << 13) +# define G4X_DM_DONE (1 << 12) +# define G4X_FT_DONE (1 << 11) +# define G4X_DG_DONE (1 << 10) +# define G4X_SI_DONE (1 << 9) +# define G4X_SO_DONE (1 << 8) +# define G4X_PL_DONE (1 << 7) +# define G4X_WIZ_DONE (1 << 6) +# define G4X_URB_DONE (1 << 5) +# define G4X_SF_DONE (1 << 4) +# define G4X_CL_DONE (1 << 3) +# define G4X_GS_DONE (1 << 2) +# define G4X_VS0_DONE (1 << 1) +# define G4X_VF_DONE (1 << 0) + +#define GEN6_INSTDONE_2 0x207c +# define GEN6_GAM_DONE (1 << 31) +# define GEN6_CS_DONE (1 << 30) +# define GEN6_WMBE_DONE (1 << 29) +# define GEN6_SVRW_DONE (1 << 28) +# define GEN6_RCC_DONE (1 << 27) +# define GEN6_SVG_DONE (1 << 26) +# define GEN6_ISC_DONE (1 << 25) +# define GEN6_MT_DONE (1 << 24) +# define GEN6_RCPFE_DONE (1 << 23) +# define GEN6_RCPBE_DONE (1 << 22) +# define GEN6_VDI_DONE (1 << 21) +# define GEN6_RCZ_DONE (1 << 20) +# define GEN6_DAP_DONE (1 << 19) +# define GEN6_PSD_DONE (1 << 18) +# define GEN6_IZ_DONE (1 << 17) +# define GEN6_WMFE_DONE (1 << 16) +# define GEN6_SVSM_DONE (1 << 15) +# define GEN6_QC_DONE (1 << 14) +# define GEN6_FL_DONE (1 << 13) +# define GEN6_SC_DONE (1 << 12) +# define GEN6_DM_DONE (1 << 11) +# define GEN6_FT_DONE (1 << 10) +# define GEN6_DG_DONE (1 << 9) +# define GEN6_SI_DONE (1 << 8) +# define GEN6_SO_DONE (1 << 7) +# define GEN6_PL_DONE (1 << 6) +# define GEN6_VME_DONE (1 << 5) +# define GEN6_SF_DONE (1 << 4) +# define GEN6_CL_DONE (1 << 3) +# define GEN6_GS_DONE (1 << 2) +# define GEN6_VS0_DONE (1 << 1) +# define GEN6_VF_DONE (1 << 0) + +#define CACHE_MODE_0 0x2120 +#define CACHE_MODE_1 0x2124 +#define MI_MODE 0x209c +#define MI_DISPLAY_POWER_DOWN 0x20e0 +#define MI_ARB_STATE 0x20e4 +#define MI_RDRET_STATE 0x20fc + +/* Start addresses for each of the primary rings: + */ +#define PR0_STR 0x20f0 +#define PR1_STR 0x20f4 +#define PR2_STR 0x20f8 + +#define WIZ_CTL 0x7c00 +#define WIZ_CTL_SINGLE_SUBSPAN (1<<6) +#define WIZ_CTL_IGNORE_STALLS (1<<5) + +#define SVG_WORK_CTL 0x7408 + +#define TS_CTL 0x7e00 +#define TS_MUX_ERR_CODE (0<<8) +#define TS_MUX_URB_0 (1<<8) +#define TS_MUX_DISPATCH_ID_0 (10<<8) +#define TS_MUX_ERR_CODE_VALID (15<<8) +#define TS_MUX_TID_0 (16<<8) +#define TS_MUX_EUID_0 (18<<8) +#define TS_MUX_FFID_0 (22<<8) +#define TS_MUX_EOT (26<<8) +#define TS_MUX_SIDEBAND_0 (27<<8) +#define TS_SNAP_ALL_CHILD (1<<2) +#define TS_SNAP_ALL_ROOT (1<<1) +#define TS_SNAP_ENABLE (1<<0) + +#define TS_DEBUG_DATA 0x7e0c + +#define TD_CTL 0x8000 +#define TD_CTL2 0x8004 + + +#define ECOSKPD 0x21d0 +#define EXCC 0x2028 + +/* I965 debug regs: + */ +#define IA_VERTICES_COUNT_QW 0x2310 +#define IA_PRIMITIVES_COUNT_QW 0x2318 +#define VS_INVOCATION_COUNT_QW 0x2320 +#define GS_INVOCATION_COUNT_QW 0x2328 +#define GS_PRIMITIVES_COUNT_QW 0x2330 +#define CL_INVOCATION_COUNT_QW 0x2338 +#define CL_PRIMITIVES_COUNT_QW 0x2340 +#define PS_INVOCATION_COUNT_QW 0x2348 +#define PS_DEPTH_COUNT_QW 0x2350 +#define TIMESTAMP_QW 0x2358 +#define CLKCMP_QW 0x2360 + + + + + + +/* General error reporting regs, p296 + */ +#define EIR 0x20B0 +#define EMR 0x20B4 +#define ESR 0x20B8 +# define ERR_VERTEX_MAX (1 << 5) /* lpt/cst */ +# define ERR_PGTBL_ERROR (1 << 4) +# define ERR_DISPLAY_OVERLAY_UNDERRUN (1 << 3) +# define ERR_MAIN_MEMORY_REFRESH (1 << 1) +# define ERR_INSTRUCTION_ERROR (1 << 0) + + +/* Interrupt Control Registers + * - new bits for i810 + * - new register hwstam (mask) + */ +#define HWS_PGA 0x2080 +#define PWRCTXA 0x2088 /* 965GM+ only */ +#define PWRCTX_EN (1<<0) +#define HWSTAM 0x2098 /* p290 */ +#define IER 0x20a0 /* p291 */ +#define IIR 0x20a4 /* p292 */ +#define IMR 0x20a8 /* p293 */ +#define ISR 0x20ac /* p294 */ +#define HW_ERROR 0x8000 +#define SYNC_STATUS_TOGGLE 0x1000 +#define DPY_0_FLIP_PENDING 0x0800 +#define DPY_1_FLIP_PENDING 0x0400 /* not implemented on i810 */ +#define OVL_0_FLIP_PENDING 0x0200 +#define OVL_1_FLIP_PENDING 0x0100 /* not implemented on i810 */ +#define DPY_0_VBLANK 0x0080 +#define DPY_0_EVENT 0x0040 +#define DPY_1_VBLANK 0x0020 /* not implemented on i810 */ +#define DPY_1_EVENT 0x0010 /* not implemented on i810 */ +#define HOST_PORT_EVENT 0x0008 /* */ +#define CAPTURE_EVENT 0x0004 /* */ +#define USER_DEFINED 0x0002 +#define BREAKPOINT 0x0001 + + +#define INTR_RESERVED (0x6000 | \ + DPY_1_FLIP_PENDING | \ + OVL_1_FLIP_PENDING | \ + DPY_1_VBLANK | \ + DPY_1_EVENT | \ + HOST_PORT_EVENT | \ + CAPTURE_EVENT ) + +/* FIFO Watermark and Burst Length Control Register + * + * - different offset and contents on i810 (p299) (fewer bits per field) + * - some overlay fields added + * - what does it all mean? + */ +#define FWATER_BLC 0x20d8 +#define FWATER_BLC2 0x20dc +#define MM_BURST_LENGTH 0x00700000 +#define MM_FIFO_WATERMARK 0x0001F000 +#define LM_BURST_LENGTH 0x00000700 +#define LM_FIFO_WATERMARK 0x0000001F + + +/* Fence/Tiling ranges [0..7] + */ +#define FENCE 0x2000 +#define FENCE_NR 8 + +#define FENCE_NEW 0x3000 +#define FENCE_NEW_NR 16 + +#define FENCE_LINEAR 0 +#define FENCE_XMAJOR 1 +#define FENCE_YMAJOR 2 + +#define I915G_FENCE_START_MASK 0x0ff00000 + +#define I830_FENCE_START_MASK 0x07f80000 + +#define FENCE_START_MASK 0x03F80000 +#define FENCE_X_MAJOR 0x00000000 +#define FENCE_Y_MAJOR 0x00001000 +#define FENCE_SIZE_MASK 0x00000700 +#define FENCE_SIZE_512K 0x00000000 +#define FENCE_SIZE_1M 0x00000100 +#define FENCE_SIZE_2M 0x00000200 +#define FENCE_SIZE_4M 0x00000300 +#define FENCE_SIZE_8M 0x00000400 +#define FENCE_SIZE_16M 0x00000500 +#define FENCE_SIZE_32M 0x00000600 +#define FENCE_SIZE_64M 0x00000700 +#define I915G_FENCE_SIZE_1M 0x00000000 +#define I915G_FENCE_SIZE_2M 0x00000100 +#define I915G_FENCE_SIZE_4M 0x00000200 +#define I915G_FENCE_SIZE_8M 0x00000300 +#define I915G_FENCE_SIZE_16M 0x00000400 +#define I915G_FENCE_SIZE_32M 0x00000500 +#define I915G_FENCE_SIZE_64M 0x00000600 +#define I915G_FENCE_SIZE_128M 0x00000700 +#define I965_FENCE_X_MAJOR 0x00000000 +#define I965_FENCE_Y_MAJOR 0x00000002 +#define FENCE_PITCH_1 0x00000000 +#define FENCE_PITCH_2 0x00000010 +#define FENCE_PITCH_4 0x00000020 +#define FENCE_PITCH_8 0x00000030 +#define FENCE_PITCH_16 0x00000040 +#define FENCE_PITCH_32 0x00000050 +#define FENCE_PITCH_64 0x00000060 +#define FENCE_VALID 0x00000001 + + +/* Registers to control page table, p274 + */ +#define PGETBL_CTL 0x2020 +#define PGETBL_ADDR_MASK 0xFFFFF000 +#define PGETBL_ENABLE_MASK 0x00000001 +#define PGETBL_ENABLED 0x00000001 +/** Added in 965G, this field has the actual size of the global GTT */ +#define PGETBL_SIZE_MASK 0x0000000e +#define PGETBL_SIZE_512KB (0 << 1) +#define PGETBL_SIZE_256KB (1 << 1) +#define PGETBL_SIZE_128KB (2 << 1) +#define PGETBL_SIZE_1MB (3 << 1) +#define PGETBL_SIZE_2MB (4 << 1) +#define PGETBL_SIZE_1_5MB (5 << 1) +#define G33_PGETBL_SIZE_MASK (3 << 8) +#define G33_PGETBL_SIZE_1M (1 << 8) +#define G33_PGETBL_SIZE_2M (2 << 8) + +#define I830_PTE_BASE 0x10000 +#define PTE_ADDRESS_MASK 0xfffff000 +#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */ +#define PTE_MAPPING_TYPE_UNCACHED (0 << 1) +#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */ +#define PTE_MAPPING_TYPE_CACHED (3 << 1) +#define PTE_MAPPING_TYPE_MASK (3 << 1) +#define PTE_VALID (1 << 0) + +/** @defgroup PGE_ERR + * @{ + */ +/** Page table debug register for i845 */ +#define PGE_ERR 0x2024 +#define PGE_ERR_ADDR_MASK 0xFFFFF000 +#define PGE_ERR_ID_MASK 0x00000038 +#define PGE_ERR_CAPTURE 0x00000000 +#define PGE_ERR_OVERLAY 0x00000008 +#define PGE_ERR_DISPLAY 0x00000010 +#define PGE_ERR_HOST 0x00000018 +#define PGE_ERR_RENDER 0x00000020 +#define PGE_ERR_BLITTER 0x00000028 +#define PGE_ERR_MAPPING 0x00000030 +#define PGE_ERR_CMD_PARSER 0x00000038 +#define PGE_ERR_TYPE_MASK 0x00000007 +#define PGE_ERR_INV_TABLE 0x00000000 +#define PGE_ERR_INV_PTE 0x00000001 +#define PGE_ERR_MIXED_TYPES 0x00000002 +#define PGE_ERR_PAGE_MISS 0x00000003 +#define PGE_ERR_ILLEGAL_TRX 0x00000004 +#define PGE_ERR_LOCAL_MEM 0x00000005 +#define PGE_ERR_TILED 0x00000006 +/** @} */ + +/** @defgroup PGTBL_ER + * @{ + */ +/** Page table debug register for i945 */ +# define PGTBL_ER 0x2024 +# define PGTBL_ERR_MT_TILING (1 << 27) +# define PGTBL_ERR_MT_GTT_PTE (1 << 26) +# define PGTBL_ERR_LC_TILING (1 << 25) +# define PGTBL_ERR_LC_GTT_PTE (1 << 24) +# define PGTBL_ERR_BIN_VERTEXDATA_GTT_PTE (1 << 23) +# define PGTBL_ERR_BIN_INSTRUCTION_GTT_PTE (1 << 22) +# define PGTBL_ERR_CS_VERTEXDATA_GTT_PTE (1 << 21) +# define PGTBL_ERR_CS_INSTRUCTION_GTT_PTE (1 << 20) +# define PGTBL_ERR_CS_GTT (1 << 19) +# define PGTBL_ERR_OVERLAY_TILING (1 << 18) +# define PGTBL_ERR_OVERLAY_GTT_PTE (1 << 16) +# define PGTBL_ERR_DISPC_TILING (1 << 14) +# define PGTBL_ERR_DISPC_GTT_PTE (1 << 12) +# define PGTBL_ERR_DISPB_TILING (1 << 10) +# define PGTBL_ERR_DISPB_GTT_PTE (1 << 8) +# define PGTBL_ERR_DISPA_TILING (1 << 6) +# define PGTBL_ERR_DISPA_GTT_PTE (1 << 4) +# define PGTBL_ERR_HOST_PTE_DATA (1 << 1) +# define PGTBL_ERR_HOST_GTT_PTE (1 << 0) +/** @} */ + +/* Ring buffer registers, p277, overview p19 + */ +#define LP_RING 0x2030 +#define HP_RING 0x2040 + +#define RING_TAIL 0x00 +#define TAIL_ADDR 0x000FFFF8 +#define I830_TAIL_MASK 0x001FFFF8 + +#define RING_HEAD 0x04 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define I830_HEAD_MASK 0x001FFFFC + +#define RING_START 0x08 +#define START_ADDR 0x03FFFFF8 +#define I830_RING_START_MASK 0xFFFFF000 + +#define RING_LEN 0x0C +#define RING_NR_PAGES 0x001FF000 +#define I830_RING_NR_PAGES 0x001FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 + + + +/* BitBlt Instructions + * + * There are many more masks & ranges yet to add. + */ +#define BR00_BITBLT_CLIENT 0x40000000 +#define BR00_OP_COLOR_BLT 0x10000000 +#define BR00_OP_SRC_COPY_BLT 0x10C00000 +#define BR00_OP_FULL_BLT 0x11400000 +#define BR00_OP_MONO_SRC_BLT 0x11800000 +#define BR00_OP_MONO_SRC_COPY_BLT 0x11000000 +#define BR00_OP_MONO_PAT_BLT 0x11C00000 +#define BR00_OP_MONO_SRC_COPY_IMMEDIATE_BLT (0x61 << 22) +#define BR00_OP_TEXT_IMMEDIATE_BLT 0xc000000 + + +#define BR00_TPCY_DISABLE 0x00000000 +#define BR00_TPCY_ENABLE 0x00000010 + +#define BR00_TPCY_ROP 0x00000000 +#define BR00_TPCY_NO_ROP 0x00000020 +#define BR00_TPCY_EQ 0x00000000 +#define BR00_TPCY_NOT_EQ 0x00000040 + +#define BR00_PAT_MSB_FIRST 0x00000000 /* ? */ + +#define BR00_PAT_VERT_ALIGN 0x000000e0 + +#define BR00_LENGTH 0x0000000F + +#define BR09_DEST_ADDR 0x03FFFFFF + +#define BR11_SOURCE_PITCH 0x00003FFF + +#define BR12_SOURCE_ADDR 0x03FFFFFF + +#define BR13_SOLID_PATTERN 0x80000000 +#define BR13_RIGHT_TO_LEFT 0x40000000 +#define BR13_LEFT_TO_RIGHT 0x00000000 +#define BR13_MONO_TRANSPCY 0x20000000 +#define BR13_MONO_PATN_TRANS 0x10000000 +#define BR13_USE_DYN_DEPTH 0x04000000 +#define BR13_DYN_8BPP 0x00000000 +#define BR13_DYN_16BPP 0x01000000 +#define BR13_DYN_24BPP 0x02000000 +#define BR13_ROP_MASK 0x00FF0000 +#define BR13_DEST_PITCH 0x0000FFFF +#define BR13_PITCH_SIGN_BIT 0x00008000 + +#define BR14_DEST_HEIGHT 0xFFFF0000 +#define BR14_DEST_WIDTH 0x0000FFFF + +#define BR15_PATTERN_ADDR 0x03FFFFFF + +#define BR16_SOLID_PAT_COLOR 0x00FFFFFF +#define BR16_BACKGND_PAT_CLR 0x00FFFFFF + +#define BR17_FGND_PAT_CLR 0x00FFFFFF + +#define BR18_SRC_BGND_CLR 0x00FFFFFF +#define BR19_SRC_FGND_CLR 0x00FFFFFF + + +/* Instruction parser instructions + */ + +#define INST_PARSER_CLIENT 0x00000000 +#define INST_OP_FLUSH 0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) + + +/* Registers in the i810 host-pci bridge pci config space which affect + * the i810 graphics operations. + */ +#define SMRAM_MISCC 0x70 +#define GMS 0x000000c0 +#define GMS_DISABLE 0x00000000 +#define GMS_ENABLE_BARE 0x00000040 +#define GMS_ENABLE_512K 0x00000080 +#define GMS_ENABLE_1M 0x000000c0 +#define USMM 0x00000030 +#define USMM_DISABLE 0x00000000 +#define USMM_TSEG_ZERO 0x00000010 +#define USMM_TSEG_512K 0x00000020 +#define USMM_TSEG_1M 0x00000030 +#define GFX_MEM_WIN_SIZE 0x00010000 +#define GFX_MEM_WIN_32M 0x00010000 +#define GFX_MEM_WIN_64M 0x00000000 + +/* Overkill? I don't know. Need to figure out top of mem to make the + * SMRAM calculations come out. Linux seems to have problems + * detecting it all on its own, so this seems a reasonable double + * check to any user supplied 'mem=...' boot param. + * + * ... unfortunately this reg doesn't work according to spec on the + * test hardware. + */ +#define WHTCFG_PAMR_DRP 0x50 +#define SYS_DRAM_ROW_0_SHIFT 16 +#define SYS_DRAM_ROW_1_SHIFT 20 +#define DRAM_MASK 0x0f +#define DRAM_VALUE_0 0 +#define DRAM_VALUE_1 8 +/* No 2 value defined */ +#define DRAM_VALUE_3 16 +#define DRAM_VALUE_4 16 +#define DRAM_VALUE_5 24 +#define DRAM_VALUE_6 32 +#define DRAM_VALUE_7 32 +#define DRAM_VALUE_8 48 +#define DRAM_VALUE_9 64 +#define DRAM_VALUE_A 64 +#define DRAM_VALUE_B 96 +#define DRAM_VALUE_C 128 +#define DRAM_VALUE_D 128 +#define DRAM_VALUE_E 192 +#define DRAM_VALUE_F 256 /* nice one, geezer */ +#define LM_FREQ_MASK 0x10 +#define LM_FREQ_133 0x10 +#define LM_FREQ_100 0x00 + + + + +/* These are 3d state registers, but the state is invarient, so we let + * the X server handle it: + */ + + + +/* GFXRENDERSTATE_COLOR_CHROMA_KEY, p135 + */ +#define GFX_OP_COLOR_CHROMA_KEY ((0x3<<29)|(0x1d<<24)|(0x2<<16)|0x1) +#define CC1_UPDATE_KILL_WRITE (1<<28) +#define CC1_ENABLE_KILL_WRITE (1<<27) +#define CC1_DISABLE_KILL_WRITE 0 +#define CC1_UPDATE_COLOR_IDX (1<<26) +#define CC1_UPDATE_CHROMA_LOW (1<<25) +#define CC1_UPDATE_CHROMA_HI (1<<24) +#define CC1_CHROMA_LOW_MASK ((1<<24)-1) +#define CC2_COLOR_IDX_SHIFT 24 +#define CC2_COLOR_IDX_MASK (0xff<<24) +#define CC2_CHROMA_HI_MASK ((1<<24)-1) + + +#define GFX_CMD_CONTEXT_SEL ((0<<29)|(0x5<<23)) +#define CS_UPDATE_LOAD (1<<17) +#define CS_UPDATE_USE (1<<16) +#define CS_UPDATE_LOAD (1<<17) +#define CS_LOAD_CTX0 0 +#define CS_LOAD_CTX1 (1<<8) +#define CS_USE_CTX0 0 +#define CS_USE_CTX1 (1<<0) + +/* I810 LCD/TV registers */ +#define LCD_TV_HTOTAL 0x60000 +#define LCD_TV_C 0x60018 +#define LCD_TV_OVRACT 0x6001C + +#define LCD_TV_ENABLE (1 << 31) +#define LCD_TV_VGAMOD (1 << 28) + +/* I830 CRTC registers */ +#define HTOTAL_A 0x60000 +#define HBLANK_A 0x60004 +#define HSYNC_A 0x60008 +#define VTOTAL_A 0x6000c +#define VBLANK_A 0x60010 +#define VSYNC_A 0x60014 +#define PIPEASRC 0x6001c +#define BCLRPAT_A 0x60020 +#define VSYNCSHIFT_A 0x60028 + +#define HTOTAL_B 0x61000 +#define HBLANK_B 0x61004 +#define HSYNC_B 0x61008 +#define VTOTAL_B 0x6100c +#define VBLANK_B 0x61010 +#define VSYNC_B 0x61014 +#define PIPEBSRC 0x6101c +#define BCLRPAT_B 0x61020 +#define VSYNCSHIFT_B 0x61028 + +#define HTOTAL_C 0x62000 +#define HBLANK_C 0x62004 +#define HSYNC_C 0x62008 +#define VTOTAL_C 0x6200c +#define VBLANK_C 0x62010 +#define VSYNC_C 0x62014 +#define PIPECSRC 0x6201c +#define BCLRPAT_C 0x62020 +#define VSYNCSHIFT_C 0x62028 + +#define PP_STATUS 0x61200 +# define PP_ON (1 << 31) +/** + * Indicates that all dependencies of the panel are on: + * + * - PLL enabled + * - pipe enabled + * - LVDS/DVOB/DVOC on + */ +# define PP_READY (1 << 30) +# define PP_SEQUENCE_NONE (0 << 28) +# define PP_SEQUENCE_ON (1 << 28) +# define PP_SEQUENCE_OFF (2 << 28) +# define PP_SEQUENCE_MASK 0x30000000 + +#define PP_CONTROL 0x61204 +# define POWER_DOWN_ON_RESET (1 << 1) +# define POWER_TARGET_ON (1 << 0) + +#define PP_ON_DELAYS 0x61208 +#define PP_OFF_DELAYS 0x6120c +#define PP_DIVISOR 0x61210 + +#define PFIT_CONTROL 0x61230 +# define PFIT_ENABLE (1 << 31) +/* Pre-965 */ +# define VERT_INTERP_DISABLE (0 << 10) +# define VERT_INTERP_BILINEAR (1 << 10) +# define VERT_INTERP_MASK (3 << 10) +# define VERT_AUTO_SCALE (1 << 9) +# define HORIZ_INTERP_DISABLE (0 << 6) +# define HORIZ_INTERP_BILINEAR (1 << 6) +# define HORIZ_INTERP_MASK (3 << 6) +# define HORIZ_AUTO_SCALE (1 << 5) +# define PANEL_8TO6_DITHER_ENABLE (1 << 3) +/* 965+ */ +# define PFIT_PIPE_MASK (3 << 29) +# define PFIT_PIPE_SHIFT 29 +# define PFIT_SCALING_MODE_MASK (7 << 26) +# define PFIT_SCALING_AUTO (0 << 26) +# define PFIT_SCALING_PROGRAMMED (1 << 26) +# define PFIT_SCALING_PILLAR (2 << 26) +# define PFIT_SCALING_LETTER (3 << 26) +# define PFIT_FILTER_SELECT_MASK (3 << 24) +# define PFIT_FILTER_FUZZY (0 << 24) +# define PFIT_FILTER_CRISP (1 << 24) +# define PFIT_FILTER_MEDIAN (2 << 24) + +#define PFIT_PGM_RATIOS 0x61234 +/* Pre-965 */ +# define PFIT_VERT_SCALE_SHIFT 20 +# define PFIT_VERT_SCALE_MASK 0xfff00000 +# define PFIT_HORIZ_SCALE_SHIFT 4 +# define PFIT_HORIZ_SCALE_MASK 0x0000fff0 +/* 965+ */ +# define PFIT_VERT_SCALE_SHIFT_965 16 +# define PFIT_VERT_SCALE_MASK_965 0x1fff0000 +# define PFIT_HORIZ_SCALE_SHIFT_965 0 +# define PFIT_HORIZ_SCALE_MASK_965 0x00001fff + +#define DPLL_A 0x06014 +#define DPLL_B 0x06018 +# define DPLL_VCO_ENABLE (1 << 31) +# define DPLL_DVO_HIGH_SPEED (1 << 30) +# define DPLL_SYNCLOCK_ENABLE (1 << 29) +# define DPLL_VGA_MODE_DIS (1 << 28) +# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ +# define DPLLB_MODE_LVDS (2 << 26) /* i915 */ +# define DPLL_MODE_MASK (3 << 26) +# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ +# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ +# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ +# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ +# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ +# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ +# define DPLL_FPA01_P1_POST_DIV_MASK_IGD 0x00ff8000 /* IGD */ +/** + * The i830 generation, in DAC/serial mode, defines p1 as two plus this + * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set. + */ +# define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 +/** + * The i830 generation, in LVDS mode, defines P1 as the bit number set within + * this field (only one bit may be set). + */ +# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 +# define DPLL_FPA01_P1_POST_DIV_SHIFT 16 +# define DPLL_FPA01_P1_POST_DIV_SHIFT_IGD 15 +# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */ +# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ +# define PLL_REF_INPUT_DREFCLK (0 << 13) +# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ +# define PLL_REF_INPUT_SUPER_SSC (1 << 13) /* Ironlake: 120M SSC */ +# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */ +# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) +# define PLL_REF_INPUT_MASK (3 << 13) +# define PLL_REF_INPUT_DMICLK (5 << 13) /* Ironlake: DMI refclk */ +# define PLL_LOAD_PULSE_PHASE_SHIFT 9 +/* + * Parallel to Serial Load Pulse phase selection. + * Selects the phase for the 10X DPLL clock for the PCIe + * digital display port. The range is 4 to 13; 10 or more + * is just a flip delay. The default is 6 + */ +# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) +# define DISPLAY_RATE_SELECT_FPA1 (1 << 8) +/* Ironlake */ +# define PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT 9 +# define PLL_REF_SDVO_HDMI_MULTIPLIER_MASK (7 << 9) +# define PLL_REF_SDVO_HDMI_MULTIPLIER(x) (((x)-1)<< PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT) +# define DPLL_FPA1_P1_POST_DIV_SHIFT 0 +# define DPLL_FPA1_P1_POST_DIV_MASK 0xff + +/** + * SDVO multiplier for 945G/GM. Not used on 965. + * + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ +# define SDVO_MULTIPLIER_MASK 0x000000ff +# define SDVO_MULTIPLIER_SHIFT_HIRES 4 +# define SDVO_MULTIPLIER_SHIFT_VGA 0 + +/** @defgroup DPLL_MD + * @{ + */ +/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */ +#define DPLL_A_MD 0x0601c +/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */ +#define DPLL_B_MD 0x06020 +/** + * UDI pixel divider, controlling how many pixels are stuffed into a packet. + * + * Value is pixels minus 1. Must be set to 1 pixel for SDVO. + */ +# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 +# define DPLL_MD_UDI_DIVIDER_SHIFT 24 +/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ +# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 +# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 +/** + * SDVO/UDI pixel multiplier. + * + * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus + * clock rate is 10 times the DPLL clock. At low resolution/refresh rate + * modes, the bus rate would be below the limits, so SDVO allows for stuffing + * dummy bytes in the datastream at an increased clock rate, with both sides of + * the link knowing how many bytes are fill. + * + * So, for a mode with a dotclock of 65Mhz, we would want to double the clock + * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be + * set to 130Mhz, and the SDVO multiplier set to 2x in this register and + * through an SDVO command. + * + * This register field has values of multiplication factor minus 1, with + * a maximum multiplier of 5 for SDVO. + */ +# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 +# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 +/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. + * This best be set to the default value (3) or the CRT won't work. No, + * I don't entirely understand what this does... + */ +# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f +# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 +/** @} */ + +#define DPLL_TEST 0x606c +# define DPLLB_TEST_SDVO_DIV_1 (0 << 22) +# define DPLLB_TEST_SDVO_DIV_2 (1 << 22) +# define DPLLB_TEST_SDVO_DIV_4 (2 << 22) +# define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) +# define DPLLB_TEST_N_BYPASS (1 << 19) +# define DPLLB_TEST_M_BYPASS (1 << 18) +# define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) +# define DPLLA_TEST_N_BYPASS (1 << 3) +# define DPLLA_TEST_M_BYPASS (1 << 2) +# define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) + +#define D_STATE 0x6104 +#define DSPCLK_GATE_D 0x6200 +# define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */ +# define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */ +# define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* 965 */ +# define VRDUNIT_CLOCK_GATE_DISABLE (1 << 27) /* 965 */ +# define AUDUNIT_CLOCK_GATE_DISABLE (1 << 26) /* 965 */ +# define DPUNIT_A_CLOCK_GATE_DISABLE (1 << 25) /* 965 */ +# define DPCUNIT_CLOCK_GATE_DISABLE (1 << 24) /* 965 */ +# define TVRUNIT_CLOCK_GATE_DISABLE (1 << 23) /* 915-945 */ +# define TVCUNIT_CLOCK_GATE_DISABLE (1 << 22) /* 915-945 */ +# define TVFUNIT_CLOCK_GATE_DISABLE (1 << 21) /* 915-945 */ +# define TVEUNIT_CLOCK_GATE_DISABLE (1 << 20) /* 915-945 */ +# define DVSUNIT_CLOCK_GATE_DISABLE (1 << 19) /* 915-945 */ +# define DSSUNIT_CLOCK_GATE_DISABLE (1 << 18) /* 915-945 */ +# define DDBUNIT_CLOCK_GATE_DISABLE (1 << 17) /* 915-945 */ +# define DPRUNIT_CLOCK_GATE_DISABLE (1 << 16) /* 915-945 */ +# define DPFUNIT_CLOCK_GATE_DISABLE (1 << 15) /* 915-945 */ +# define DPBMUNIT_CLOCK_GATE_DISABLE (1 << 14) /* 915-945 */ +# define DPLSUNIT_CLOCK_GATE_DISABLE (1 << 13) /* 915-945 */ +# define DPLUNIT_CLOCK_GATE_DISABLE (1 << 12) /* 915-945 */ +# define DPOUNIT_CLOCK_GATE_DISABLE (1 << 11) +# define DPBUNIT_CLOCK_GATE_DISABLE (1 << 10) +# define DCUNIT_CLOCK_GATE_DISABLE (1 << 9) +# define DPUNIT_CLOCK_GATE_DISABLE (1 << 8) +# define VRUNIT_CLOCK_GATE_DISABLE (1 << 7) /* 915+: reserved */ +# define OVHUNIT_CLOCK_GATE_DISABLE (1 << 6) /* 830-865 */ +# define DPIOUNIT_CLOCK_GATE_DISABLE (1 << 6) /* 915-945 */ +# define OVFUNIT_CLOCK_GATE_DISABLE (1 << 5) +# define OVBUNIT_CLOCK_GATE_DISABLE (1 << 4) +/** + * This bit must be set on the 830 to prevent hangs when turning off the + * overlay scaler. + */ +# define OVRUNIT_CLOCK_GATE_DISABLE (1 << 3) +# define OVCUNIT_CLOCK_GATE_DISABLE (1 << 2) +# define OVUUNIT_CLOCK_GATE_DISABLE (1 << 1) +# define ZVUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 830 */ +# define OVLUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 845,865 */ + +#define RENCLK_GATE_D1 0x6204 +# define BLITTER_CLOCK_GATE_DISABLE (1 << 13) /* 945GM only */ +# define MPEG_CLOCK_GATE_DISABLE (1 << 12) /* 945GM only */ +# define PC_FE_CLOCK_GATE_DISABLE (1 << 11) +# define PC_BE_CLOCK_GATE_DISABLE (1 << 10) +# define WINDOWER_CLOCK_GATE_DISABLE (1 << 9) +# define INTERPOLATOR_CLOCK_GATE_DISABLE (1 << 8) +# define COLOR_CALCULATOR_CLOCK_GATE_DISABLE (1 << 7) +# define MOTION_COMP_CLOCK_GATE_DISABLE (1 << 6) +# define MAG_CLOCK_GATE_DISABLE (1 << 5) +/** This bit must be unset on 855,865 */ +# define MECI_CLOCK_GATE_DISABLE (1 << 4) +# define DCMP_CLOCK_GATE_DISABLE (1 << 3) +# define MEC_CLOCK_GATE_DISABLE (1 << 2) +# define MECO_CLOCK_GATE_DISABLE (1 << 1) +/** This bit must be set on 855,865. */ +# define SV_CLOCK_GATE_DISABLE (1 << 0) +# define I915_MPEG_CLOCK_GATE_DISABLE (1 << 16) +# define I915_VLD_IP_PR_CLOCK_GATE_DISABLE (1 << 15) +# define I915_MOTION_COMP_CLOCK_GATE_DISABLE (1 << 14) +# define I915_BD_BF_CLOCK_GATE_DISABLE (1 << 13) +# define I915_SF_SE_CLOCK_GATE_DISABLE (1 << 12) +# define I915_WM_CLOCK_GATE_DISABLE (1 << 11) +# define I915_IZ_CLOCK_GATE_DISABLE (1 << 10) +# define I915_PI_CLOCK_GATE_DISABLE (1 << 9) +# define I915_DI_CLOCK_GATE_DISABLE (1 << 8) +# define I915_SH_SV_CLOCK_GATE_DISABLE (1 << 7) +# define I915_PL_DG_QC_FT_CLOCK_GATE_DISABLE (1 << 6) +# define I915_SC_CLOCK_GATE_DISABLE (1 << 5) +# define I915_FL_CLOCK_GATE_DISABLE (1 << 4) +# define I915_DM_CLOCK_GATE_DISABLE (1 << 3) +# define I915_PS_CLOCK_GATE_DISABLE (1 << 2) +# define I915_CC_CLOCK_GATE_DISABLE (1 << 1) +# define I915_BY_CLOCK_GATE_DISABLE (1 << 0) + +# define I965_RCZ_CLOCK_GATE_DISABLE (1 << 30) +/** This bit must always be set on 965G/965GM */ +# define I965_RCC_CLOCK_GATE_DISABLE (1 << 29) +# define I965_RCPB_CLOCK_GATE_DISABLE (1 << 28) +# define I965_DAP_CLOCK_GATE_DISABLE (1 << 27) +# define I965_ROC_CLOCK_GATE_DISABLE (1 << 26) +# define I965_GW_CLOCK_GATE_DISABLE (1 << 25) +# define I965_TD_CLOCK_GATE_DISABLE (1 << 24) +/** This bit must always be set on 965G */ +# define I965_ISC_CLOCK_GATE_DISABLE (1 << 23) +# define I965_IC_CLOCK_GATE_DISABLE (1 << 22) +# define I965_EU_CLOCK_GATE_DISABLE (1 << 21) +# define I965_IF_CLOCK_GATE_DISABLE (1 << 20) +# define I965_TC_CLOCK_GATE_DISABLE (1 << 19) +# define I965_SO_CLOCK_GATE_DISABLE (1 << 17) +# define I965_FBC_CLOCK_GATE_DISABLE (1 << 16) +# define I965_MARI_CLOCK_GATE_DISABLE (1 << 15) +# define I965_MASF_CLOCK_GATE_DISABLE (1 << 14) +# define I965_MAWB_CLOCK_GATE_DISABLE (1 << 13) +# define I965_EM_CLOCK_GATE_DISABLE (1 << 12) +# define I965_UC_CLOCK_GATE_DISABLE (1 << 11) +# define I965_SI_CLOCK_GATE_DISABLE (1 << 6) +# define I965_MT_CLOCK_GATE_DISABLE (1 << 5) +# define I965_PL_CLOCK_GATE_DISABLE (1 << 4) +# define I965_DG_CLOCK_GATE_DISABLE (1 << 3) +# define I965_QC_CLOCK_GATE_DISABLE (1 << 2) +# define I965_FT_CLOCK_GATE_DISABLE (1 << 1) +# define I965_DM_CLOCK_GATE_DISABLE (1 << 0) + +#define RENCLK_GATE_D2 0x6208 +#define VF_UNIT_CLOCK_GATE_DISABLE (1 << 9) +#define GS_UNIT_CLOCK_GATE_DISABLE (1 << 7) +#define CL_UNIT_CLOCK_GATE_DISABLE (1 << 6) +#define RAMCLK_GATE_D 0x6210 /* CRL only */ +#define DEUC 0x6214 /* CRL only */ + +/* + * This is a PCI config space register to manipulate backlight brightness + * It is used when the BLM_LEGACY_MODE is turned on. When enabled, the first + * byte of this config register sets brightness within the range from + * 0 to 0xff + */ +#define LEGACY_BACKLIGHT_BRIGHTNESS 0xf4 + +#define BLC_PWM_CTL 0x61254 +#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) +#define BACKLIGHT_MODULATION_FREQ_SHIFT2 (16) +/** + * This is the most significant 15 bits of the number of backlight cycles in a + * complete cycle of the modulated backlight control. + * + * The actual value is this field multiplied by two. + */ +#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) +#define BACKLIGHT_MODULATION_FREQ_MASK2 (0xffff << 16) +#define BLM_LEGACY_MODE (1 << 16) + +/** + * This is the number of cycles out of the backlight modulation cycle for which + * the backlight is on. + * + * This field must be no greater than the number of cycles in the complete + * backlight modulation cycle. + */ +#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) +#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) + +/* On 965+ backlight control is in another register */ +#define BLC_PWM_CTL2 0x61250 +#define BLM_LEGACY_MODE2 (1 << 30) + +#define BLM_CTL 0x61260 +#define BLM_THRESHOLD_0 0x61270 +#define BLM_THRESHOLD_1 0x61274 +#define BLM_THRESHOLD_2 0x61278 +#define BLM_THRESHOLD_3 0x6127c +#define BLM_THRESHOLD_4 0x61280 +#define BLM_THRESHOLD_5 0x61284 + +#define BLM_ACCUMULATOR_0 0x61290 +#define BLM_ACCUMULATOR_1 0x61294 +#define BLM_ACCUMULATOR_2 0x61298 +#define BLM_ACCUMULATOR_3 0x6129c +#define BLM_ACCUMULATOR_4 0x612a0 +#define BLM_ACCUMULATOR_5 0x612a4 + +#define FPA0 0x06040 +#define FPA1 0x06044 +#define FPB0 0x06048 +#define FPB1 0x0604c +# define FP_N_DIV_MASK 0x003f0000 +# define FP_N_IGD_DIV_MASK 0x00ff0000 +# define FP_N_DIV_SHIFT 16 +# define FP_M1_DIV_MASK 0x00003f00 +# define FP_M1_DIV_SHIFT 8 +# define FP_M2_DIV_MASK 0x0000003f +# define FP_M2_IGD_DIV_MASK 0x000000ff +# define FP_M2_DIV_SHIFT 0 + +#define PORT_HOTPLUG_EN 0x61110 +# define HDMIB_HOTPLUG_INT_EN (1 << 29) +# define HDMIC_HOTPLUG_INT_EN (1 << 28) +# define HDMID_HOTPLUG_INT_EN (1 << 27) +# define SDVOB_HOTPLUG_INT_EN (1 << 26) +# define SDVOC_HOTPLUG_INT_EN (1 << 25) +# define TV_HOTPLUG_INT_EN (1 << 18) +# define CRT_HOTPLUG_INT_EN (1 << 9) +# define CRT_HOTPLUG_ACTIVATION_PERIOD_32 (0 << 8) +/* must use period 64 on GM45 according to docs */ +# define CRT_HOTPLUG_ACTIVATION_PERIOD_64 (1 << 8) +# define CRT_HOTPLUG_DAC_ON_TIME_2M (0 << 7) +# define CRT_HOTPLUG_DAC_ON_TIME_4M (1 << 7) +# define CRT_HOTPLUG_VOLTAGE_COMPARE_40 (0 << 5) +# define CRT_HOTPLUG_VOLTAGE_COMPARE_50 (1 << 5) +# define CRT_HOTPLUG_VOLTAGE_COMPARE_60 (2 << 5) +# define CRT_HOTPLUG_VOLTAGE_COMPARE_70 (3 << 5) +# define CRT_HOTPLUG_VOLTAGE_COMPARE_MASK (3 << 5) +# define CRT_HOTPLUG_DETECT_DELAY_1G (0 << 4) +# define CRT_HOTPLUG_DETECT_DELAY_2G (1 << 4) +# define CRT_HOTPLUG_FORCE_DETECT (1 << 3) +# define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) +# define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) +# define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */ + +#define PORT_HOTPLUG_STAT 0x61114 +# define HDMIB_HOTPLUG_INT_STATUS (1 << 29) +# define HDMIC_HOTPLUG_INT_STATUS (1 << 28) +# define HDMID_HOTPLUG_INT_STATUS (1 << 27) +# define CRT_HOTPLUG_INT_STATUS (1 << 11) +# define TV_HOTPLUG_INT_STATUS (1 << 10) +# define CRT_HOTPLUG_MONITOR_MASK (3 << 8) +# define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) +# define CRT_HOTPLUG_MONITOR_MONO (2 << 8) +# define CRT_HOTPLUG_MONITOR_NONE (0 << 8) +# define SDVOC_HOTPLUG_INT_STATUS (1 << 7) +# define SDVOB_HOTPLUG_INT_STATUS (1 << 6) + +#define SDVOB 0x61140 +#define SDVOC 0x61160 +#define SDVO_ENABLE (1 << 31) +#define SDVO_PIPE_B_SELECT (1 << 30) +#define SDVO_STALL_SELECT (1 << 29) +#define SDVO_INTERRUPT_ENABLE (1 << 26) +/** + * 915G/GM SDVO pixel multiplier. + * + * Programmed value is multiplier - 1, up to 5x. + * + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ +#define SDVO_PORT_MULTIPLY_MASK (7 << 23) +#define SDVO_PORT_MULTIPLY_SHIFT 23 +#define SDVO_PHASE_SELECT_MASK (15 << 19) +#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) +#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) +#define SDVOC_GANG_MODE (1 << 16) +#define SDVO_ENCODING_SDVO (0x0 << 10) +#define SDVO_ENCODING_HDMI (0x2 << 10) +/** Requird for HDMI operation */ +#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) +#define SDVO_BORDER_ENABLE (1 << 7) +#define SDVO_AUDIO_ENABLE (1 << 6) +/** New with 965, default is to be set */ +#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4) +/** New with 965, default is to be set */ +#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3) +/** 915/945 only, read-only bit */ +#define SDVOB_PCIE_CONCURRENCY (1 << 3) +#define SDVO_DETECTED (1 << 2) +/* Bits to be preserved when writing */ +#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14)) +#define SDVOC_PRESERVE_MASK (1 << 17) + +#define UDIB_SVB_SHB_CODES 0x61144 +#define UDIB_SHA_BLANK_CODES 0x61148 +#define UDIB_START_END_FILL_CODES 0x6114c + + +#define SDVOUDI 0x61150 + +#define I830_HTOTAL_MASK 0xfff0000 +#define I830_HACTIVE_MASK 0x7ff + +#define I830_HBLANKEND_MASK 0xfff0000 +#define I830_HBLANKSTART_MASK 0xfff + +#define I830_HSYNCEND_MASK 0xfff0000 +#define I830_HSYNCSTART_MASK 0xfff + +#define I830_VTOTAL_MASK 0xfff0000 +#define I830_VACTIVE_MASK 0x7ff + +#define I830_VBLANKEND_MASK 0xfff0000 +#define I830_VBLANKSTART_MASK 0xfff + +#define I830_VSYNCEND_MASK 0xfff0000 +#define I830_VSYNCSTART_MASK 0xfff + +#define I830_PIPEA_HORZ_MASK 0x7ff0000 +#define I830_PIPEA_VERT_MASK 0x7ff + +#define ADPA 0x61100 +#define ADPA_DAC_ENABLE (1<<31) +#define ADPA_DAC_DISABLE 0 +#define ADPA_PIPE_SELECT_MASK (1<<30) +#define ADPA_PIPE_A_SELECT 0 +#define ADPA_PIPE_B_SELECT (1<<30) +#define ADPA_USE_VGA_HVPOLARITY (1<<15) +#define ADPA_SETS_HVPOLARITY 0 +#define ADPA_VSYNC_CNTL_DISABLE (1<<11) +#define ADPA_VSYNC_CNTL_ENABLE 0 +#define ADPA_HSYNC_CNTL_DISABLE (1<<10) +#define ADPA_HSYNC_CNTL_ENABLE 0 +#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) +#define ADPA_VSYNC_ACTIVE_LOW 0 +#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) +#define ADPA_HSYNC_ACTIVE_LOW 0 + +#define PCH_DSPCLK_GATE_D 0x42020 +#define PCH_DSPRAMCLK_GATE_D 0x42024 +#define PCH_3DCGDIS0 0x46020 +#define PCH_3DCGDIS1 0x46024 +#define PCH_3DRAMCGDIS0 0x46028 +#define SOUTH_DSPCLK_GATE_D 0xc2020 + +#define CPU_eDP_A 0x64000 +#define PCH_DP_B 0xe4100 +#define PCH_DP_C 0xe4200 +#define PCH_DP_D 0xe4300 + +#define DVOA 0x61120 +#define DVOB 0x61140 +#define DVOC 0x61160 +#define DVO_ENABLE (1 << 31) +#define DVO_PIPE_B_SELECT (1 << 30) +#define DVO_PIPE_STALL_UNUSED (0 << 28) +#define DVO_PIPE_STALL (1 << 28) +#define DVO_PIPE_STALL_TV (2 << 28) +#define DVO_PIPE_STALL_MASK (3 << 28) +#define DVO_USE_VGA_SYNC (1 << 15) +#define DVO_DATA_ORDER_I740 (0 << 14) +#define DVO_DATA_ORDER_FP (1 << 14) +#define DVO_VSYNC_DISABLE (1 << 11) +#define DVO_HSYNC_DISABLE (1 << 10) +#define DVO_VSYNC_TRISTATE (1 << 9) +#define DVO_HSYNC_TRISTATE (1 << 8) +#define DVO_BORDER_ENABLE (1 << 7) +#define DVO_DATA_ORDER_GBRG (1 << 6) +#define DVO_DATA_ORDER_RGGB (0 << 6) +#define DVO_DATA_ORDER_GBRG_ERRATA (0 << 6) +#define DVO_DATA_ORDER_RGGB_ERRATA (1 << 6) +#define DVO_VSYNC_ACTIVE_HIGH (1 << 4) +#define DVO_HSYNC_ACTIVE_HIGH (1 << 3) +#define DVO_BLANK_ACTIVE_HIGH (1 << 2) +#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */ +#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */ +#define DVO_PRESERVE_MASK (0x7<<24) + +#define DVOA_SRCDIM 0x61124 +#define DVOB_SRCDIM 0x61144 +#define DVOC_SRCDIM 0x61164 +#define DVO_SRCDIM_HORIZONTAL_SHIFT 12 +#define DVO_SRCDIM_VERTICAL_SHIFT 0 + +/** @defgroup LVDS + * @{ + */ +/** + * This register controls the LVDS output enable, pipe selection, and data + * format selection. + * + * All of the clock/data pairs are force powered down by power sequencing. + */ +#define LVDS 0x61180 +/** + * Enables the LVDS port. This bit must be set before DPLLs are enabled, as + * the DPLL semantics change when the LVDS is assigned to that pipe. + */ +# define LVDS_PORT_EN (1 << 31) +/** Selects pipe B for LVDS data. Must be set on pre-965. */ +# define LVDS_PIPEB_SELECT (1 << 30) + +/* on 965, dithering is enabled in this register, not PFIT_CONTROL */ +# define LVDS_DITHER_ENABLE (1 << 25) + +/* + * Selects between .0 and .1 formats: + * + * 0 = 1x18.0, 2x18.0, 1x24.0 or 2x24.0 + * 1 = 1x24.1 or 2x24.1 + */ +# define LVDS_DATA_FORMAT_DOT_ONE (1 << 24) + +/* Using LE instead of HS on second channel control signal */ +# define LVDS_LE_CONTROL_ENABLE (1 << 23) + +/* Using LF instead of VS on second channel control signal */ +# define LVDS_LF_CONTROL_ENABLE (1 << 22) + +/* invert vsync signal polarity */ +# define LVDS_VSYNC_POLARITY_INVERT (1 << 21) + +/* invert hsync signal polarity */ +# define LVDS_HSYNC_POLARITY_INVERT (1 << 20) + +/* invert display enable signal polarity */ +# define LVDS_DE_POLARITY_INVERT (1 << 19) + +/* + * Control signals for second channel, ignored in single channel modes + */ + +/* send DE, HS, VS on second channel */ +# define LVDS_SECOND_CHANNEL_DE_HS_VS (0 << 17) + +# define LVDS_SECOND_CHANNEL_RESERVED (1 << 17) + +/* Send zeros instead of DE, HS, VS on second channel */ +# define LVDS_SECOND_CHANNEL_ZEROS (2 << 17) + +/* Set DE=0, HS=LE, VS=LF on second channel */ +# define LVDS_SECOND_CHANNEL_HS_VS (3 << 17) + +/* + * Send duplicate data for channel reserved bits, otherwise send zeros + */ +# define LVDS_CHANNEL_DUP_RESERVED (1 << 16) + +/* + * Enable border for unscaled (or aspect-scaled) display + */ +# define LVDS_BORDER_ENABLE (1 << 15) + +/* + * Tri-state the LVDS buffers when powered down, otherwise + * they are set to 0V + */ +# define LVDS_POWER_DOWN_TRI_STATE (1 << 10) + +/** + * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per + * pixel. + */ +# define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) +# define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) +# define LVDS_A0A2_CLKA_POWER_UP (3 << 8) +/** + * Controls the A3 data pair, which contains the additional LSBs for 24 bit + * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be + * on. + */ +# define LVDS_A3_POWER_MASK (3 << 6) +# define LVDS_A3_POWER_DOWN (0 << 6) +# define LVDS_A3_POWER_UP (3 << 6) +/** + * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP + * is set. + */ +# define LVDS_CLKB_POWER_MASK (3 << 4) +# define LVDS_CLKB_POWER_DOWN (0 << 4) +# define LVDS_CLKB_POWER_UP (3 << 4) + +/** + * Controls the B0-B3 data pairs. This must be set to match the DPLL p2 + * setting for whether we are in dual-channel mode. The B3 pair will + * additionally only be powered up when LVDS_A3_POWER_UP is set. + */ +# define LVDS_B0B3_POWER_MASK (3 << 2) +# define LVDS_B0B3_POWER_DOWN (0 << 2) +# define LVDS_B0B3_POWER_UP (3 << 2) + +/** @} */ + +#define DP_B 0x64100 +#define DPB_AUX_CH_CTL 0x64110 +#define DPB_AUX_CH_DATA1 0x64114 +#define DPB_AUX_CH_DATA2 0x64118 +#define DPB_AUX_CH_DATA3 0x6411c +#define DPB_AUX_CH_DATA4 0x64120 +#define DPB_AUX_CH_DATA5 0x64124 + +#define DP_C 0x64200 +#define DPC_AUX_CH_CTL 0x64210 +#define DPC_AUX_CH_DATA1 0x64214 +#define DPC_AUX_CH_DATA2 0x64218 +#define DPC_AUX_CH_DATA3 0x6421c +#define DPC_AUX_CH_DATA4 0x64220 +#define DPC_AUX_CH_DATA5 0x64224 + +#define DP_D 0x64300 +#define DPD_AUX_CH_CTL 0x64310 +#define DPD_AUX_CH_DATA1 0x64314 +#define DPD_AUX_CH_DATA2 0x64318 +#define DPD_AUX_CH_DATA3 0x6431c +#define DPD_AUX_CH_DATA4 0x64320 +#define DPD_AUX_CH_DATA5 0x64324 + +/* + * Two channel clock control. Turn this on if you need clkb for two channel mode + * Overridden by global LVDS power sequencing + */ + +/* clkb off */ +# define LVDS_CLKB_POWER_DOWN (0 << 4) + +/* powered up, but clkb forced to 0 */ +# define LVDS_CLKB_POWER_PARTIAL (1 << 4) + +/* clock B running */ +# define LVDS_CLKB_POWER_UP (3 << 4) + +/* + * Two channel mode B0-B2 control. Sets state when power is on. + * Set to POWER_DOWN in single channel mode, other settings enable + * two channel mode. The CLKB power control controls whether that clock + * is enabled during two channel mode. + * + */ +/* Everything is off, including B3 and CLKB */ +# define LVDS_B_POWER_DOWN (0 << 2) + +/* B0, B1, B2 and data lines forced to 0. timing is active */ +# define LVDS_B_POWER_PARTIAL (1 << 2) + +/* data lines active (both timing and colour) */ +# define LVDS_B_POWER_UP (3 << 2) + +/** @defgroup TV_CTL + * @{ + */ +#define TV_CTL 0x68000 +/** Enables the TV encoder */ +# define TV_ENC_ENABLE (1 << 31) +/** Sources the TV encoder input from pipe B instead of A. */ +# define TV_ENC_PIPEB_SELECT (1 << 30) +/** Outputs composite video (DAC A only) */ +# define TV_ENC_OUTPUT_COMPOSITE (0 << 28) +/** Outputs SVideo video (DAC B/C) */ +# define TV_ENC_OUTPUT_SVIDEO (1 << 28) +/** Outputs Component video (DAC A/B/C) */ +# define TV_ENC_OUTPUT_COMPONENT (2 << 28) +/** Outputs Composite and SVideo (DAC A/B/C) */ +# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE (3 << 28) +# define TV_TRILEVEL_SYNC (1 << 21) +/** Enables slow sync generation (945GM only) */ +# define TV_SLOW_SYNC (1 << 20) +/** Selects 4x oversampling for 480i and 576p */ +# define TV_OVERSAMPLE_4X (0 << 18) +/** Selects 2x oversampling for 720p and 1080i */ +# define TV_OVERSAMPLE_2X (1 << 18) +/** Selects no oversampling for 1080p */ +# define TV_OVERSAMPLE_NONE (2 << 18) +/** Selects 8x oversampling */ +# define TV_OVERSAMPLE_8X (3 << 18) +/** Selects progressive mode rather than interlaced */ +# define TV_PROGRESSIVE (1 << 17) +/** Sets the colorburst to PAL mode. Required for non-M PAL modes. */ +# define TV_PAL_BURST (1 << 16) +/** Field for setting delay of Y compared to C */ +# define TV_YC_SKEW_MASK (7 << 12) +/** Enables a fix for 480p/576p standard definition modes on the 915GM only */ +# define TV_ENC_SDP_FIX (1 << 11) +/** + * Enables a fix for the 915GM only. + * + * Not sure what it does. + */ +# define TV_ENC_C0_FIX (1 << 10) +/** Bits that must be preserved by software */ +# define TV_CTL_SAVE ((1 << 11) | (3 << 9) | (7 << 6) | 0xf) +# define TV_FUSE_STATE_MASK (3 << 4) +/** Read-only state that reports all features enabled */ +# define TV_FUSE_STATE_ENABLED (0 << 4) +/** Read-only state that reports that Macrovision is disabled in hardware*/ +# define TV_FUSE_STATE_NO_MACROVISION (1 << 4) +/** Read-only state that reports that TV-out is disabled in hardware. */ +# define TV_FUSE_STATE_DISABLED (2 << 4) +/** Normal operation */ +# define TV_TEST_MODE_NORMAL (0 << 0) +/** Encoder test pattern 1 - combo pattern */ +# define TV_TEST_MODE_PATTERN_1 (1 << 0) +/** Encoder test pattern 2 - full screen vertical 75% color bars */ +# define TV_TEST_MODE_PATTERN_2 (2 << 0) +/** Encoder test pattern 3 - full screen horizontal 75% color bars */ +# define TV_TEST_MODE_PATTERN_3 (3 << 0) +/** Encoder test pattern 4 - random noise */ +# define TV_TEST_MODE_PATTERN_4 (4 << 0) +/** Encoder test pattern 5 - linear color ramps */ +# define TV_TEST_MODE_PATTERN_5 (5 << 0) +/** + * This test mode forces the DACs to 50% of full output. + * + * This is used for load detection in combination with TVDAC_SENSE_MASK + */ +# define TV_TEST_MODE_MONITOR_DETECT (7 << 0) +# define TV_TEST_MODE_MASK (7 << 0) +/** @} */ + +/** @defgroup TV_DAC + * @{ + */ +#define TV_DAC 0x68004 +/** + * Reports that DAC state change logic has reported change (RO). + * + * This gets cleared when TV_DAC_STATE_EN is cleared +*/ +# define TVDAC_STATE_CHG (1 << 31) +# define TVDAC_SENSE_MASK (7 << 28) +/** Reports that DAC A voltage is above the detect threshold */ +# define TVDAC_A_SENSE (1 << 30) +/** Reports that DAC B voltage is above the detect threshold */ +# define TVDAC_B_SENSE (1 << 29) +/** Reports that DAC C voltage is above the detect threshold */ +# define TVDAC_C_SENSE (1 << 28) +/** + * Enables DAC state detection logic, for load-based TV detection. + * + * The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set + * to off, for load detection to work. + */ +# define TVDAC_STATE_CHG_EN (1 << 27) +/** Sets the DAC A sense value to high */ +# define TVDAC_A_SENSE_CTL (1 << 26) +/** Sets the DAC B sense value to high */ +# define TVDAC_B_SENSE_CTL (1 << 25) +/** Sets the DAC C sense value to high */ +# define TVDAC_C_SENSE_CTL (1 << 24) +/** Overrides the ENC_ENABLE and DAC voltage levels */ +# define DAC_CTL_OVERRIDE (1 << 7) +/** Sets the slew rate. Must be preserved in software */ +# define ENC_TVDAC_SLEW_FAST (1 << 6) +# define DAC_A_1_3_V (0 << 4) +# define DAC_A_1_1_V (1 << 4) +# define DAC_A_0_7_V (2 << 4) +# define DAC_A_OFF (3 << 4) +# define DAC_B_1_3_V (0 << 2) +# define DAC_B_1_1_V (1 << 2) +# define DAC_B_0_7_V (2 << 2) +# define DAC_B_OFF (3 << 2) +# define DAC_C_1_3_V (0 << 0) +# define DAC_C_1_1_V (1 << 0) +# define DAC_C_0_7_V (2 << 0) +# define DAC_C_OFF (3 << 0) +/** @} */ + +/** + * CSC coefficients are stored in a floating point format with 9 bits of + * mantissa and 2 or 3 bits of exponent. The exponent is represented as 2**-n, + * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with + * -1 (0x3) being the only legal negative value. + */ +#define TV_CSC_Y 0x68010 +# define TV_RY_MASK 0x07ff0000 +# define TV_RY_SHIFT 16 +# define TV_GY_MASK 0x00000fff +# define TV_GY_SHIFT 0 + +#define TV_CSC_Y2 0x68014 +# define TV_BY_MASK 0x07ff0000 +# define TV_BY_SHIFT 16 +/** + * Y attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AY_MASK 0x000003ff +# define TV_AY_SHIFT 0 + +#define TV_CSC_U 0x68018 +# define TV_RU_MASK 0x07ff0000 +# define TV_RU_SHIFT 16 +# define TV_GU_MASK 0x000007ff +# define TV_GU_SHIFT 0 + +#define TV_CSC_U2 0x6801c +# define TV_BU_MASK 0x07ff0000 +# define TV_BU_SHIFT 16 +/** + * U attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AU_MASK 0x000003ff +# define TV_AU_SHIFT 0 + +#define TV_CSC_V 0x68020 +# define TV_RV_MASK 0x0fff0000 +# define TV_RV_SHIFT 16 +# define TV_GV_MASK 0x000007ff +# define TV_GV_SHIFT 0 + +#define TV_CSC_V2 0x68024 +# define TV_BV_MASK 0x07ff0000 +# define TV_BV_SHIFT 16 +/** + * V attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AV_MASK 0x000007ff +# define TV_AV_SHIFT 0 + +/** @defgroup TV_CSC_KNOBS + * @{ + */ +#define TV_CLR_KNOBS 0x68028 +/** 2s-complement brightness adjustment */ +# define TV_BRIGHTNESS_MASK 0xff000000 +# define TV_BRIGHTNESS_SHIFT 24 +/** Contrast adjustment, as a 2.6 unsigned floating point number */ +# define TV_CONTRAST_MASK 0x00ff0000 +# define TV_CONTRAST_SHIFT 16 +/** Saturation adjustment, as a 2.6 unsigned floating point number */ +# define TV_SATURATION_MASK 0x0000ff00 +# define TV_SATURATION_SHIFT 8 +/** Hue adjustment, as an integer phase angle in degrees */ +# define TV_HUE_MASK 0x000000ff +# define TV_HUE_SHIFT 0 +/** @} */ + +/** @defgroup TV_CLR_LEVEL + * @{ + */ +#define TV_CLR_LEVEL 0x6802c +/** Controls the DAC level for black */ +# define TV_BLACK_LEVEL_MASK 0x01ff0000 +# define TV_BLACK_LEVEL_SHIFT 16 +/** Controls the DAC level for blanking */ +# define TV_BLANK_LEVEL_MASK 0x000001ff +# define TV_BLANK_LEVEL_SHIFT 0 +/* @} */ + +/** @defgroup TV_H_CTL_1 + * @{ + */ +#define TV_H_CTL_1 0x68030 +/** Number of pixels in the hsync. */ +# define TV_HSYNC_END_MASK 0x1fff0000 +# define TV_HSYNC_END_SHIFT 16 +/** Total number of pixels minus one in the line (display and blanking). */ +# define TV_HTOTAL_MASK 0x00001fff +# define TV_HTOTAL_SHIFT 0 +/** @} */ + +/** @defgroup TV_H_CTL_2 + * @{ + */ +#define TV_H_CTL_2 0x68034 +/** Enables the colorburst (needed for non-component color) */ +# define TV_BURST_ENA (1 << 31) +/** Offset of the colorburst from the start of hsync, in pixels minus one. */ +# define TV_HBURST_START_SHIFT 16 +# define TV_HBURST_START_MASK 0x1fff0000 +/** Length of the colorburst */ +# define TV_HBURST_LEN_SHIFT 0 +# define TV_HBURST_LEN_MASK 0x0001fff +/** @} */ + +/** @defgroup TV_H_CTL_3 + * @{ + */ +#define TV_H_CTL_3 0x68038 +/** End of hblank, measured in pixels minus one from start of hsync */ +# define TV_HBLANK_END_SHIFT 16 +# define TV_HBLANK_END_MASK 0x1fff0000 +/** Start of hblank, measured in pixels minus one from start of hsync */ +# define TV_HBLANK_START_SHIFT 0 +# define TV_HBLANK_START_MASK 0x0001fff +/** @} */ + +/** @defgroup TV_V_CTL_1 + * @{ + */ +#define TV_V_CTL_1 0x6803c +/** XXX */ +# define TV_NBR_END_SHIFT 16 +# define TV_NBR_END_MASK 0x07ff0000 +/** XXX */ +# define TV_VI_END_F1_SHIFT 8 +# define TV_VI_END_F1_MASK 0x00003f00 +/** XXX */ +# define TV_VI_END_F2_SHIFT 0 +# define TV_VI_END_F2_MASK 0x0000003f +/** @} */ + +/** @defgroup TV_V_CTL_2 + * @{ + */ +#define TV_V_CTL_2 0x68040 +/** Length of vsync, in half lines */ +# define TV_VSYNC_LEN_MASK 0x07ff0000 +# define TV_VSYNC_LEN_SHIFT 16 +/** Offset of the start of vsync in field 1, measured in one less than the + * number of half lines. + */ +# define TV_VSYNC_START_F1_MASK 0x00007f00 +# define TV_VSYNC_START_F1_SHIFT 8 +/** + * Offset of the start of vsync in field 2, measured in one less than the + * number of half lines. + */ +# define TV_VSYNC_START_F2_MASK 0x0000007f +# define TV_VSYNC_START_F2_SHIFT 0 +/** @} */ + +/** @defgroup TV_V_CTL_3 + * @{ + */ +#define TV_V_CTL_3 0x68044 +/** Enables generation of the equalization signal */ +# define TV_EQUAL_ENA (1 << 31) +/** Length of vsync, in half lines */ +# define TV_VEQ_LEN_MASK 0x007f0000 +# define TV_VEQ_LEN_SHIFT 16 +/** Offset of the start of equalization in field 1, measured in one less than + * the number of half lines. + */ +# define TV_VEQ_START_F1_MASK 0x0007f00 +# define TV_VEQ_START_F1_SHIFT 8 +/** + * Offset of the start of equalization in field 2, measured in one less than + * the number of half lines. + */ +# define TV_VEQ_START_F2_MASK 0x000007f +# define TV_VEQ_START_F2_SHIFT 0 +/** @} */ + +/** @defgroup TV_V_CTL_4 + * @{ + */ +#define TV_V_CTL_4 0x68048 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F1_MASK 0x003f0000 +# define TV_VBURST_START_F1_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F1_MASK 0x000000ff +# define TV_VBURST_END_F1_SHIFT 0 +/** @} */ + +/** @defgroup TV_V_CTL_5 + * @{ + */ +#define TV_V_CTL_5 0x6804c +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F2_MASK 0x003f0000 +# define TV_VBURST_START_F2_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F2_MASK 0x000000ff +# define TV_VBURST_END_F2_SHIFT 0 +/** @} */ + +/** @defgroup TV_V_CTL_6 + * @{ + */ +#define TV_V_CTL_6 0x68050 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F3_MASK 0x003f0000 +# define TV_VBURST_START_F3_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F3_MASK 0x000000ff +# define TV_VBURST_END_F3_SHIFT 0 +/** @} */ + +/** @defgroup TV_V_CTL_7 + * @{ + */ +#define TV_V_CTL_7 0x68054 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F4_MASK 0x003f0000 +# define TV_VBURST_START_F4_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F4_MASK 0x000000ff +# define TV_VBURST_END_F4_SHIFT 0 +/** @} */ + +/** @defgroup TV_SC_CTL_1 + * @{ + */ +#define TV_SC_CTL_1 0x68060 +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA1_EN (1 << 31) +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA2_EN (1 << 30) +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA3_EN (1 << 29) +/** Sets the subcarrier DDA to reset frequency every other field */ +# define TV_SC_RESET_EVERY_2 (0 << 24) +/** Sets the subcarrier DDA to reset frequency every fourth field */ +# define TV_SC_RESET_EVERY_4 (1 << 24) +/** Sets the subcarrier DDA to reset frequency every eighth field */ +# define TV_SC_RESET_EVERY_8 (2 << 24) +/** Sets the subcarrier DDA to never reset the frequency */ +# define TV_SC_RESET_NEVER (3 << 24) +/** Sets the peak amplitude of the colorburst.*/ +# define TV_BURST_LEVEL_MASK 0x00ff0000 +# define TV_BURST_LEVEL_SHIFT 16 +/** Sets the increment of the first subcarrier phase generation DDA */ +# define TV_SCDDA1_INC_MASK 0x00000fff +# define TV_SCDDA1_INC_SHIFT 0 +/** @} */ + +/** @defgroup TV_SC_CTL_2 + * @{ + */ +#define TV_SC_CTL_2 0x68064 +/** Sets the rollover for the second subcarrier phase generation DDA */ +# define TV_SCDDA2_SIZE_MASK 0x7fff0000 +# define TV_SCDDA2_SIZE_SHIFT 16 +/** Sets the increent of the second subcarrier phase generation DDA */ +# define TV_SCDDA2_INC_MASK 0x00007fff +# define TV_SCDDA2_INC_SHIFT 0 +/** @} */ + +/** @defgroup TV_SC_CTL_3 + * @{ + */ +#define TV_SC_CTL_3 0x68068 +/** Sets the rollover for the third subcarrier phase generation DDA */ +# define TV_SCDDA3_SIZE_MASK 0x7fff0000 +# define TV_SCDDA3_SIZE_SHIFT 16 +/** Sets the increent of the third subcarrier phase generation DDA */ +# define TV_SCDDA3_INC_MASK 0x00007fff +# define TV_SCDDA3_INC_SHIFT 0 +/** @} */ + +/** @defgroup TV_WIN_POS + * @{ + */ +#define TV_WIN_POS 0x68070 +/** X coordinate of the display from the start of horizontal active */ +# define TV_XPOS_MASK 0x1fff0000 +# define TV_XPOS_SHIFT 16 +/** Y coordinate of the display from the start of vertical active (NBR) */ +# define TV_YPOS_MASK 0x00000fff +# define TV_YPOS_SHIFT 0 +/** @} */ + +/** @defgroup TV_WIN_SIZE + * @{ + */ +#define TV_WIN_SIZE 0x68074 +/** Horizontal size of the display window, measured in pixels*/ +# define TV_XSIZE_MASK 0x1fff0000 +# define TV_XSIZE_SHIFT 16 +/** + * Vertical size of the display window, measured in pixels. + * + * Must be even for interlaced modes. + */ +# define TV_YSIZE_MASK 0x00000fff +# define TV_YSIZE_SHIFT 0 +/** @} */ + +/** @defgroup TV_FILTER_CTL_1 + * @{ + */ +#define TV_FILTER_CTL_1 0x68080 +/** + * Enables automatic scaling calculation. + * + * If set, the rest of the registers are ignored, and the calculated values can + * be read back from the register. + */ +# define TV_AUTO_SCALE (1 << 31) +/** + * Disables the vertical filter. + * + * This is required on modes more than 1024 pixels wide */ +# define TV_V_FILTER_BYPASS (1 << 29) +/** Enables adaptive vertical filtering */ +# define TV_VADAPT (1 << 28) +# define TV_VADAPT_MODE_MASK (3 << 26) +/** Selects the least adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_LEAST (0 << 26) +/** Selects the moderately adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_MODERATE (1 << 26) +/** Selects the most adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_MOST (3 << 26) +/** + * Sets the horizontal scaling factor. + * + * This should be the fractional part of the horizontal scaling factor divided + * by the oversampling rate. TV_HSCALE should be less than 1, and set to: + * + * (src width - 1) / ((oversample * dest width) - 1) + */ +# define TV_HSCALE_FRAC_MASK 0x00003fff +# define TV_HSCALE_FRAC_SHIFT 0 +/** @} */ + +/** @defgroup TV_FILTER_CTL_2 + * @{ + */ +#define TV_FILTER_CTL_2 0x68084 +/** + * Sets the integer part of the 3.15 fixed-point vertical scaling factor. + * + * TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1) + */ +# define TV_VSCALE_INT_MASK 0x00038000 +# define TV_VSCALE_INT_SHIFT 15 +/** + * Sets the fractional part of the 3.15 fixed-point vertical scaling factor. + * + * \sa TV_VSCALE_INT_MASK + */ +# define TV_VSCALE_FRAC_MASK 0x00007fff +# define TV_VSCALE_FRAC_SHIFT 0 +/** @} */ + +/** @defgroup TV_FILTER_CTL_3 + * @{ + */ +#define TV_FILTER_CTL_3 0x68088 +/** + * Sets the integer part of the 3.15 fixed-point vertical scaling factor. + * + * TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1)) + * + * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes. + */ +# define TV_VSCALE_IP_INT_MASK 0x00038000 +# define TV_VSCALE_IP_INT_SHIFT 15 +/** + * Sets the fractional part of the 3.15 fixed-point vertical scaling factor. + * + * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes. + * + * \sa TV_VSCALE_IP_INT_MASK + */ +# define TV_VSCALE_IP_FRAC_MASK 0x00007fff +# define TV_VSCALE_IP_FRAC_SHIFT 0 +/** @} */ + +/** @defgroup TV_CC_CONTROL + * @{ + */ +#define TV_CC_CONTROL 0x68090 +# define TV_CC_ENABLE (1 << 31) +/** + * Specifies which field to send the CC data in. + * + * CC data is usually sent in field 0. + */ +# define TV_CC_FID_MASK (1 << 27) +# define TV_CC_FID_SHIFT 27 +/** Sets the horizontal position of the CC data. Usually 135. */ +# define TV_CC_HOFF_MASK 0x03ff0000 +# define TV_CC_HOFF_SHIFT 16 +/** Sets the vertical position of the CC data. Usually 21 */ +# define TV_CC_LINE_MASK 0x0000003f +# define TV_CC_LINE_SHIFT 0 +/** @} */ + +/** @defgroup TV_CC_DATA + * @{ + */ +#define TV_CC_DATA 0x68094 +# define TV_CC_RDY (1 << 31) +/** Second word of CC data to be transmitted. */ +# define TV_CC_DATA_2_MASK 0x007f0000 +# define TV_CC_DATA_2_SHIFT 16 +/** First word of CC data to be transmitted. */ +# define TV_CC_DATA_1_MASK 0x0000007f +# define TV_CC_DATA_1_SHIFT 0 +/** @} + */ + +/** @{ */ +#define TV_H_LUMA_0 0x68100 +#define TV_H_LUMA_59 0x681ec +#define TV_H_CHROMA_0 0x68200 +#define TV_H_CHROMA_59 0x682ec +#define TV_V_LUMA_0 0x68300 +#define TV_V_LUMA_42 0x683a8 +#define TV_V_CHROMA_0 0x68400 +#define TV_V_CHROMA_42 0x684a8 +/** @} */ + +#define PIPEA_DSL 0x70000 + +#define PIPEACONF 0x70008 +#define PIPEACONF_ENABLE (1<<31) +#define PIPEACONF_DISABLE 0 +#define PIPEACONF_DOUBLE_WIDE (1<<30) +#define I965_PIPECONF_ACTIVE (1<<30) +#define PIPEACONF_SINGLE_WIDE 0 +#define PIPEACONF_PIPE_UNLOCKED 0 +#define PIPEACONF_PIPE_LOCKED (1<<25) +#define PIPEACONF_PALETTE 0 +#define PIPEACONF_GAMMA (1<<24) +#define PIPECONF_FORCE_BORDER (1<<25) +#define PIPECONF_PROGRESSIVE (0 << 21) +#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) +#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) +/* ironlake: gamma */ +#define PIPECONF_PALETTE_8BIT (0<<24) +#define PIPECONF_PALETTE_10BIT (1<<24) +#define PIPECONF_PALETTE_12BIT (2<<24) +#define PIPECONF_FORCE_BORDER (1<<25) +#define PIPECONF_PROGRESSIVE (0 << 21) +#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) +#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) +/* ironlake */ +#define PIPECONF_MSA_TIMING_DELAY (0<<18) /* for eDP */ +#define PIPECONF_NO_DYNAMIC_RATE_CHANGE (0 << 16) +#define PIPECONF_NO_ROTATION (0<<14) +#define PIPECONF_FULL_COLOR_RANGE (0<<13) +#define PIPECONF_CE_COLOR_RANGE (1<<13) +#define PIPECONF_COLOR_SPACE_RGB (0<<11) +#define PIPECONF_COLOR_SPACE_YUV601 (1<<11) +#define PIPECONF_COLOR_SPACE_YUV709 (2<<11) +#define PIPECONF_CONNECT_DEFAULT (0<<9) +#define PIPECONF_8BPP (0<<5) +#define PIPECONF_10BPP (1<<5) +#define PIPECONF_6BPP (2<<5) +#define PIPECONF_12BPP (3<<5) +#define PIPECONF_ENABLE_DITHER (1<<4) +#define PIPECONF_DITHER_SPATIAL (0<<2) +#define PIPECONF_DITHER_ST1 (1<<2) +#define PIPECONF_DITHER_ST2 (2<<2) +#define PIPECONF_DITHER_TEMPORAL (3<<2) + +#define PIPEAGCMAXRED 0x70010 +#define PIPEAGCMAXGREEN 0x70014 +#define PIPEAGCMAXBLUE 0x70018 +#define PIPEASTAT 0x70024 +# define FIFO_UNDERRUN (1 << 31) +# define CRC_ERROR_ENABLE (1 << 29) +# define CRC_DONE_ENABLE (1 << 28) +# define GMBUS_EVENT_ENABLE (1 << 27) +# define VSYNC_INT_ENABLE (1 << 25) +# define DLINE_COMPARE_ENABLE (1 << 24) +# define DPST_EVENT_ENABLE (1 << 23) +# define LBLC_EVENT_ENABLE (1 << 22) +# define OFIELD_INT_ENABLE (1 << 21) +# define EFIELD_INT_ENABLE (1 << 20) +# define SVBLANK_INT_ENABLE (1 << 18) +# define VBLANK_INT_ENABLE (1 << 17) +# define OREG_UPDATE_ENABLE (1 << 16) +# define CRC_ERROR_INT_STATUS (1 << 13) +# define CRC_DONE_INT_STATUS (1 << 12) +# define GMBUS_INT_STATUS (1 << 11) +# define VSYNC_INT_STATUS (1 << 9) +# define DLINE_COMPARE_STATUS (1 << 8) +# define DPST_EVENT_STATUS (1 << 7) +# define LBLC_EVENT_STATUS (1 << 6) +# define OFIELD_INT_STATUS (1 << 5) +# define EFIELD_INT_STATUS (1 << 4) +# define SVBLANK_INT_STATUS (1 << 2) +# define VBLANK_INT_STATUS (1 << 1) +# define OREG_UPDATE_STATUS (1 << 0) + + +#define DSPARB 0x70030 +#define DSPARB_CSTART_SHIFT 7 +#define DSPARB_BSTART_SHIFT 0 +#define DSPARB_BEND_SHIFT 9 /* on 855 */ +#define DSPARB_AEND_SHIFT 0 +#define DSPFW1 0x70034 +#define DSPFW2 0x70038 +#define DSPFW3 0x7003c +/* + * The two pipe frame counter registers are not synchronized, so + * reading a stable value is somewhat tricky. The following code + * should work: + * + * do { + * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> PIPE_FRAME_HIGH_SHIFT; + * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >> PIPE_FRAME_LOW_SHIFT); + * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> PIPE_FRAME_HIGH_SHIFT); + * } while (high1 != high2); + * frame = (high1 << 8) | low1; + */ +#define PIPEAFRAMEHIGH 0x70040 +#define PIPE_FRAME_HIGH_MASK 0x0000ffff +#define PIPE_FRAME_HIGH_SHIFT 0 +#define PIPEAFRAMEPIXEL 0x70044 +#define PIPE_FRAME_LOW_MASK 0xff000000 +#define PIPE_FRAME_LOW_SHIFT 24 +/* + * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register + * and is 24 bits wide. + */ +#define PIPE_PIXEL_MASK 0x00ffffff +#define PIPE_PIXEL_SHIFT 0 + +/* + * Computing GMCH M and N values. + * + * GMCH M/N = dot clock * bytes per pixel / ls_clk * # of lanes + * + * ls_clk (we assume) is the DP link clock (1.62 or 2.7 GHz) + * + * The GMCH value is used internally + */ +#define PIPEA_GMCH_DATA_M 0x70050 + +/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ +#define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25) +#define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25 + +#define PIPE_GMCH_DATA_M_MASK (0xffffff) + +#define PIPEA_GMCH_DATA_N 0x70054 +#define PIPE_GMCH_DATA_N_MASK (0xffffff) + +/* + * Computing Link M and N values. + * + * Link M / N = pixel_clock / ls_clk + * + * (the DP spec calls pixel_clock the 'strm_clk') + * + * The Link value is transmitted in the Main Stream + * Attributes and VB-ID. + */ + +#define PIPEA_DP_LINK_M 0x70060 +#define PIPEA_DP_LINK_M_MASK (0xffffff) + +#define PIPEA_DP_LINK_N 0x70064 +#define PIPEA_DP_LINK_N_MASK (0xffffff) + +#define PIPEB_DSL 0x71000 + +#define PIPEBCONF 0x71008 + +#define PIPEBGCMAXRED 0x71010 +#define PIPEBGCMAXGREEN 0x71014 +#define PIPEBGCMAXBLUE 0x71018 +#define PIPEBSTAT 0x71024 +#define PIPEBFRAMEHIGH 0x71040 +#define PIPEBFRAMEPIXEL 0x71044 + +#define PIPEB_GMCH_DATA_M 0x71050 +#define PIPEB_GMCH_DATA_N 0x71054 +#define PIPEB_DP_LINK_M 0x71060 +#define PIPEB_DP_LINK_N 0x71064 + +#define PIPECCONF 0x72008 + +#define PIPECGCMAXRED 0x72010 +#define PIPECGCMAXGREEN 0x72014 +#define PIPECGCMAXBLUE 0x72018 +#define PIPECSTAT 0x72024 +#define PIPECFRAMEHIGH 0x72040 +#define PIPECFRAMEPIXEL 0x72044 + +#define PIPEC_GMCH_DATA_M 0x72050 +#define PIPEC_GMCH_DATA_N 0x72054 +#define PIPEC_DP_LINK_M 0x72060 +#define PIPEC_DP_LINK_N 0x72064 + +#define DSPACNTR 0x70180 +#define DSPBCNTR 0x71180 +#define DSPCCNTR 0x72180 +#define DISPLAY_PLANE_ENABLE (1<<31) +#define DISPLAY_PLANE_DISABLE 0 +#define DISPLAY_PLANE_TILED (1<<10) +#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_DISABLE 0 +#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) +#define DISPPLANE_8BPP (0x2<<26) +#define DISPPLANE_15_16BPP (0x4<<26) +#define DISPPLANE_16BPP (0x5<<26) +#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) +#define DISPPLANE_32BPP (0x7<<26) +#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_SEL_PIPE_MASK (1<<24) +#define DISPPLANE_SEL_PIPE_A 0 +#define DISPPLANE_SEL_PIPE_B (1<<24) +#define DISPPLANE_SRC_KEY_ENABLE (1<<22) +#define DISPPLANE_SRC_KEY_DISABLE 0 +#define DISPPLANE_LINE_DOUBLE (1<<20) +#define DISPPLANE_NO_LINE_DOUBLE 0 +#define DISPPLANE_STEREO_POLARITY_FIRST 0 +#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) +/* plane B only */ +#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) +#define DISPPLANE_ALPHA_TRANS_DISABLE 0 +#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0 +#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) + +#define DSPABASE 0x70184 +#define DSPASTRIDE 0x70188 + +#define DSPBBASE 0x71184 +#define DSPBADDR DSPBBASE +#define DSPBSTRIDE 0x71188 + +#define DSPCBASE 0x72184 +#define DSPCADDR DSPCBASE +#define DSPCSTRIDE 0x72188 + +#define DSPAKEYVAL 0x70194 +#define DSPAKEYMASK 0x70198 + +#define DSPAPOS 0x7018C /* reserved */ +#define DSPASIZE 0x70190 +#define DSPBPOS 0x7118C +#define DSPBSIZE 0x71190 + +#define DSPASURF 0x7019C +#define DSPATILEOFF 0x701A4 + +#define DSPBSURF 0x7119C +#define DSPBTILEOFF 0x711A4 + +#define DSPCSURF 0x7219C +#define DSPCTILEOFF 0x721A4 + +#define VGACNTRL 0x71400 +# define VGA_DISP_DISABLE (1 << 31) +# define VGA_2X_MODE (1 << 30) +# define VGA_PIPE_B_SELECT (1 << 29) + +/* Various masks for reserved bits, etc. */ +#define I830_FWATER1_MASK (~((1<<11)|(1<<10)|(1<<9)| \ + (1<<8)|(1<<26)|(1<<25)|(1<<24)|(1<<5)|(1<<4)|(1<<3)| \ + (1<<2)|(1<<1)|1|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16))) +#define I830_FWATER2_MASK ~(0) + +#define DV0A_RESERVED ((1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<16)|(1<<5)|(1<<1)|1) +#define DV0B_RESERVED ((1<<27)|(1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<16)|(1<<5)|(1<<1)|1) +#define VGA0_N_DIVISOR_MASK ((1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)) +#define VGA0_M1_DIVISOR_MASK ((1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)) +#define VGA0_M2_DIVISOR_MASK ((1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1) +#define VGA0_M1M2N_RESERVED ~(VGA0_N_DIVISOR_MASK|VGA0_M1_DIVISOR_MASK|VGA0_M2_DIVISOR_MASK) +#define VGA0_POSTDIV_MASK ((1<<7)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1) +#define VGA1_POSTDIV_MASK ((1<<15)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)) +#define VGA_POSTDIV_RESERVED ~(VGA0_POSTDIV_MASK|VGA1_POSTDIV_MASK|(1<<7)|(1<<15)) +#define DPLLA_POSTDIV_MASK ((1<<23)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)) +#define DPLLA_RESERVED ((1<<27)|(1<<26)|(1<<25)|(1<<24)|(1<<22)|(1<<15)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1) +#define ADPA_RESERVED ((1<<2)|(1<<1)|1|(1<<9)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)) +#define SUPER_WORD 32 +#define BURST_A_MASK ((1<<11)|(1<<10)|(1<<9)|(1<<8)) +#define BURST_B_MASK ((1<<26)|(1<<25)|(1<<24)) +#define WATER_A_MASK ((1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1) +#define WATER_B_MASK ((1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)) +#define WATER_RESERVED ((1<<31)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<23)|(1<<22)|(1<<21)|(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<7)|(1<<6)) +#define PIPEACONF_RESERVED ((1<<29)|(1<<28)|(1<<27)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)|0xffff) +#define PIPEBCONF_RESERVED ((1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<26)|(1<<25)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)|0xffff) +#define DSPACNTR_RESERVED ((1<<23)|(1<<19)|(1<<17)|(1<<16)|0xffff) +#define DSPBCNTR_RESERVED ((1<<23)|(1<<19)|(1<<17)|(1<<16)|0x7ffe) + +#define I830_GMCH_CTRL 0x52 + +#define I830_GMCH_ENABLED 0x4 +#define I830_GMCH_MEM_MASK 0x1 +#define I830_GMCH_MEM_64M 0x1 +#define I830_GMCH_MEM_128M 0 + +#define I830_GMCH_GMS_MASK 0x70 +#define I830_GMCH_GMS_DISABLED 0x00 +#define I830_GMCH_GMS_LOCAL 0x10 +#define I830_GMCH_GMS_STOLEN_512 0x20 +#define I830_GMCH_GMS_STOLEN_1024 0x30 +#define I830_GMCH_GMS_STOLEN_8192 0x40 + +#define I830_RDRAM_CHANNEL_TYPE 0x03010 +#define I830_RDRAM_ND(x) (((x) & 0x20) >> 5) +#define I830_RDRAM_DDT(x) (((x) & 0x18) >> 3) + +#define I855_GMCH_GMS_MASK (0xF << 4) +#define I855_GMCH_GMS_DISABLED 0x00 +#define I855_GMCH_GMS_STOLEN_1M (0x1 << 4) +#define I855_GMCH_GMS_STOLEN_4M (0x2 << 4) +#define I855_GMCH_GMS_STOLEN_8M (0x3 << 4) +#define I855_GMCH_GMS_STOLEN_16M (0x4 << 4) +#define I855_GMCH_GMS_STOLEN_32M (0x5 << 4) +#define I915G_GMCH_GMS_STOLEN_48M (0x6 << 4) +#define I915G_GMCH_GMS_STOLEN_64M (0x7 << 4) +#define G33_GMCH_GMS_STOLEN_128M (0x8 << 4) +#define G33_GMCH_GMS_STOLEN_256M (0x9 << 4) +#define INTEL_GMCH_GMS_STOLEN_96M (0xa << 4) +#define INTEL_GMCH_GMS_STOLEN_160M (0xb << 4) +#define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4) +#define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4) + + +#define I85X_CAPID 0x44 +#define I85X_VARIANT_MASK 0x7 +#define I85X_VARIANT_SHIFT 5 +#define I855_GME 0x0 +#define I855_GM 0x4 +#define I852_GME 0x2 +#define I852_GM 0x5 + +#define I915_GCFGC 0xf0 +#define I915_LOW_FREQUENCY_ENABLE (1 << 7) +#define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4) +#define I915_DISPLAY_CLOCK_333_MHZ (4 << 4) +#define I915_DISPLAY_CLOCK_MASK (7 << 4) + +#define I855_HPLLCC 0xc0 +#define I855_CLOCK_CONTROL_MASK (3 << 0) +#define I855_CLOCK_133_200 (0 << 0) +#define I855_CLOCK_100_200 (1 << 0) +#define I855_CLOCK_100_133 (2 << 0) +#define I855_CLOCK_166_250 (3 << 0) + +/* BLT commands */ +#define COLOR_BLT_CMD ((2<<29)|(0x40<<22)|(0x3)) +#define COLOR_BLT_WRITE_ALPHA (1<<21) +#define COLOR_BLT_WRITE_RGB (1<<20) + +#define XY_COLOR_BLT_CMD ((2<<29)|(0x50<<22)|(0x4)) +#define XY_COLOR_BLT_WRITE_ALPHA (1<<21) +#define XY_COLOR_BLT_WRITE_RGB (1<<20) +#define XY_COLOR_BLT_TILED (1<<11) + +#define XY_SETUP_CLIP_BLT_CMD ((2<<29)|(3<<22)|1) + +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) +#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) +#define XY_SRC_COPY_BLT_DST_TILED (1<<11) + +#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|0x4) +#define SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define SRC_COPY_BLT_WRITE_RGB (1<<20) + +#define XY_PAT_BLT_IMMEDIATE ((2<<29)|(0x72<<22)) + +#define XY_MONO_PAT_BLT_CMD ((0x2<<29)|(0x52<<22)|0x7) +#define XY_MONO_PAT_VERT_SEED ((1<<10)|(1<<9)|(1<<8)) +#define XY_MONO_PAT_HORT_SEED ((1<<14)|(1<<13)|(1<<12)) +#define XY_MONO_PAT_BLT_WRITE_ALPHA (1<<21) +#define XY_MONO_PAT_BLT_WRITE_RGB (1<<20) + +#define XY_MONO_SRC_BLT_CMD ((0x2<<29)|(0x54<<22)|(0x6)) +#define XY_MONO_SRC_BLT_WRITE_ALPHA (1<<21) +#define XY_MONO_SRC_BLT_WRITE_RGB (1<<20) + +#define MI_STORE_DWORD_IMM ((0x20<<23)|2) +#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ + +#define MI_SET_CONTEXT (0x18<<23) +#define CTXT_NO_RESTORE (1) +#define CTXT_PALETTE_SAVE_DISABLE (1<<3) +#define CTXT_PALETTE_RESTORE_DISABLE (1<<2) + +/* Dword 0 */ +#define MI_VERTEX_BUFFER (0x17<<23) +#define MI_VERTEX_BUFFER_IDX(x) (x<<20) +#define MI_VERTEX_BUFFER_PITCH(x) (x<<13) +#define MI_VERTEX_BUFFER_WIDTH(x) (x<<6) +/* Dword 1 */ +#define MI_VERTEX_BUFFER_DISABLE (1) + +/* Overlay Flip */ +#define MI_OVERLAY_FLIP (0x11<<23) +#define MI_OVERLAY_FLIP_CONTINUE (0<<21) +#define MI_OVERLAY_FLIP_ON (1<<21) +#define MI_OVERLAY_FLIP_OFF (2<<21) + +/* Wait for Events */ +#define MI_WAIT_FOR_EVENT (0x03<<23) +#define MI_WAIT_FOR_PIPEB_SVBLANK (1<<18) +#define MI_WAIT_FOR_PIPEA_SVBLANK (1<<17) +#define MI_WAIT_FOR_OVERLAY_FLIP (1<<16) +#define MI_WAIT_FOR_PIPEB_VBLANK (1<<7) +#define MI_WAIT_FOR_PIPEA_VBLANK (1<<3) +#define MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW (1<<5) +#define MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW (1<<1) + +#define MI_LOAD_SCAN_LINES_INCL (0x12<<23) + +/* Flush */ +#define MI_FLUSH (0x04<<23) +#define MI_WRITE_DIRTY_STATE (1<<4) +#define MI_END_SCENE (1<<3) +#define MI_GLOBAL_SNAPSHOT_COUNT_RESET (1<<3) +#define MI_INHIBIT_RENDER_CACHE_FLUSH (1<<2) +#define MI_STATE_INSTRUCTION_CACHE_FLUSH (1<<1) +#define MI_INVALIDATE_MAP_CACHE (1<<0) +/* broadwater flush bits */ +#define BRW_MI_GLOBAL_SNAPSHOT_RESET (1 << 3) + +/* Noop */ +#define MI_NOOP 0x00 +#define MI_NOOP_WRITE_ID (1<<22) +#define MI_NOOP_ID_MASK (1<<22 - 1) + +#define STATE3D_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x01<<16)) + +/* Batch */ +#define MI_BATCH_BUFFER ((0x30 << 23) | 1) +#define MI_BATCH_BUFFER_START (0x31 << 23) +#define MI_BATCH_BUFFER_END (0xA << 23) +#define MI_BATCH_NON_SECURE (1) +#define MI_BATCH_NON_SECURE_I965 (1 << 8) + +#define MAX_DISPLAY_PIPES 2 + +typedef enum { + CrtIndex = 0, + TvIndex, + DfpIndex, + LfpIndex, + Crt2Index, + Tv2Index, + Dfp2Index, + Lfp2Index, + NumDisplayTypes +} DisplayType; + +/* What's connected to the pipes (as reported by the BIOS) */ +#define PIPE_ACTIVE_MASK 0xff +#define PIPE_CRT_ACTIVE (1 << CrtIndex) +#define PIPE_TV_ACTIVE (1 << TvIndex) +#define PIPE_DFP_ACTIVE (1 << DfpIndex) +#define PIPE_LCD_ACTIVE (1 << LfpIndex) +#define PIPE_CRT2_ACTIVE (1 << Crt2Index) +#define PIPE_TV2_ACTIVE (1 << Tv2Index) +#define PIPE_DFP2_ACTIVE (1 << Dfp2Index) +#define PIPE_LCD2_ACTIVE (1 << Lfp2Index) + +#define PIPE_SIZED_DISP_MASK (PIPE_DFP_ACTIVE | \ + PIPE_LCD_ACTIVE | \ + PIPE_DFP2_ACTIVE) + +#define PIPE_A_SHIFT 0 +#define PIPE_B_SHIFT 8 +#define PIPE_SHIFT(n) ((n) == 0 ? \ + PIPE_A_SHIFT : PIPE_B_SHIFT) + +/* + * Some BIOS scratch area registers. The 845 (and 830?) store the amount + * of video memory available to the BIOS in SWF1. + */ + +#define SWF0 0x71410 +#define SWF1 0x71414 +#define SWF2 0x71418 +#define SWF3 0x7141c +#define SWF4 0x71420 +#define SWF5 0x71424 +#define SWF6 0x71428 + +/* + * 855 scratch registers. + */ +#define SWF00 0x70410 +#define SWF01 0x70414 +#define SWF02 0x70418 +#define SWF03 0x7041c +#define SWF04 0x70420 +#define SWF05 0x70424 +#define SWF06 0x70428 + +#define SWF10 SWF0 +#define SWF11 SWF1 +#define SWF12 SWF2 +#define SWF13 SWF3 +#define SWF14 SWF4 +#define SWF15 SWF5 +#define SWF16 SWF6 + +#define SWF30 0x72414 +#define SWF31 0x72418 +#define SWF32 0x7241c + +/* + * Overlay registers. These are overlay registers accessed via MMIO. + * Those loaded via the overlay register page are defined in i830_video.c. + */ +#define OVADD 0x30000 + +#define DOVSTA 0x30008 +#define OC_BUF (0x3<<20) + +#define OGAMC5 0x30010 +#define OGAMC4 0x30014 +#define OGAMC3 0x30018 +#define OGAMC2 0x3001c +#define OGAMC1 0x30020 +#define OGAMC0 0x30024 + + +/* + * Palette registers + */ +#define PALETTE_A 0x0a000 +#define PALETTE_B 0x0a800 + +/* Framebuffer compression */ +#define FBC_CFB_BASE 0x03200 /* 4k page aligned */ +#define FBC_LL_BASE 0x03204 /* 4k page aligned */ +#define FBC_CONTROL 0x03208 +#define FBC_CTL_EN (1<<31) +#define FBC_CTL_PERIODIC (1<<30) +#define FBC_CTL_INTERVAL_SHIFT (16) +#define FBC_CTL_UNCOMPRESSIBLE (1<<14) +#define FBC_CTL_STRIDE_SHIFT (5) +#define FBC_CTL_FENCENO (1<<0) +#define FBC_COMMAND 0x0320c +#define FBC_CMD_COMPRESS (1<<0) +#define FBC_STATUS 0x03210 +#define FBC_STAT_COMPRESSING (1<<31) +#define FBC_STAT_COMPRESSED (1<<30) +#define FBC_STAT_MODIFIED (1<<29) +#define FBC_STAT_CURRENT_LINE (1<<0) +#define FBC_CONTROL2 0x03214 +#define FBC_CTL_FENCE_DBL (0<<4) +#define FBC_CTL_IDLE_IMM (0<<2) +#define FBC_CTL_IDLE_FULL (1<<2) +#define FBC_CTL_IDLE_LINE (2<<2) +#define FBC_CTL_IDLE_DEBUG (3<<2) +#define FBC_CTL_CPU_FENCE (1<<1) +#define FBC_CTL_PLANEA (0<<0) +#define FBC_CTL_PLANEB (1<<0) +#define FBC_FENCE_OFF 0x0321b +#define FBC_MOD_NUM 0x03220 +#define FBC_TAG_DEBUG 0x03300 + +#define FBC_LL_SIZE (1536) +#define FBC_LL_PAD (32) + +/* Framebuffer compression version 2 */ +#define DPFC_CB_BASE 0x3200 +#define DPFC_CONTROL 0x3208 +#define DPFC_CTL_EN (1<<31) +#define DPFC_CTL_PLANEA (0<<30) +#define DPFC_CTL_PLANEB (1<<30) +#define DPFC_CTL_FENCE_EN (1<<29) +#define DPFC_CTL_LIMIT_1X (0<<6) +#define DPFC_CTL_LIMIT_2X (1<<6) +#define DPFC_CTL_LIMIT_4X (2<<6) +#define DPFC_RECOMP_CTL 0x320c +#define DPFC_RECOMP_STALL_EN (1<<27) +#define DPFC_RECOMP_STALL_WM_SHIFT (16) +#define DPFC_RECOMP_STALL_WM_MASK (0x07ff0000) +#define DPFC_RECOMP_TIMER_COUNT_SHIFT (0) +#define DPFC_RECOMP_TIMER_COUNT_MASK (0x0000003f) +#define DPFC_STATUS 0x3210 +#define DPFC_INVAL_SEG_SHIFT (16) +#define DPFC_INVAL_SEG_MASK (0x07ff0000) +#define DPFC_COMP_SEG_SHIFT (0) +#define DPFC_COMP_SEG_MASK (0x000003ff) +#define DPFC_STATUS2 0x3214 +#define DPFC_FENCE_YOFF 0x3218 + +#define PEG_BAND_GAP_DATA 0x14d68 + +#define MCHBAR_RENDER_STANDBY 0x111B8 +#define RENDER_STANDBY_ENABLE (1 << 30) + + +/* Ironlake */ + +/* warmup time in us */ +#define WARMUP_PCH_REF_CLK_SSC_MOD 1 +#define WARMUP_PCH_FDI_RECEIVER_PLL 25 +#define WARMUP_PCH_DPLL 50 +#define WARMUP_CPU_DP_PLL 20 +#define WARMUP_CPU_FDI_TRANSMITTER_PLL 10 +#define WARMUP_DMI_LATENCY 20 +#define FDI_TRAIN_PATTERN_1_TIME 0.5 +#define FDI_TRAIN_PATTERN_2_TIME 1.5 +#define FDI_ONE_IDLE_PATTERN_TIME 31 + +#define CPU_VGACNTRL 0x41000 + +#define DIGITAL_PORT_HOTPLUG_CNTRL 0x44030 +#define DIGITAL_PORTA_HOTPLUG_ENABLE (1 << 4) +#define DIGITAL_PORTA_SHORT_PULSE_2MS (0 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_4_5MS (1 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_6MS (2 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_100MS (3 << 2) +#define DIGITAL_PORTA_NO_DETECT (0 << 0) +#define DIGITAL_PORTA_LONG_PULSE_DETECT_MASK (1 << 1) +#define DIGITAL_PORTA_SHORT_PULSE_DETECT_MASK (1 << 0) + +/* refresh rate hardware control */ +#define RR_HW_CTL 0x45300 +#define RR_HW_LOW_POWER_FRAMES_MASK 0xff +#define RR_HW_HIGH_POWER_FRAMES_MASK 0xff00 + +#define FDI_PLL_BIOS_0 0x46000 +#define FDI_PLL_BIOS_1 0x46004 +#define FDI_PLL_BIOS_2 0x46008 +#define DISPLAY_PORT_PLL_BIOS_0 0x4600c +#define DISPLAY_PORT_PLL_BIOS_1 0x46010 +#define DISPLAY_PORT_PLL_BIOS_2 0x46014 + +#define FDI_PLL_FREQ_CTL 0x46030 +#define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24) +#define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00 +#define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff + +#define PIPEA_DATA_M1 0x60030 +#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ +#define TU_SIZE_MASK 0x7e000000 +#define PIPEA_DATA_M1_OFFSET 0 +#define PIPEA_DATA_N1 0x60034 +#define PIPEA_DATA_N1_OFFSET 0 + +#define PIPEA_DATA_M2 0x60038 +#define PIPEA_DATA_M2_OFFSET 0 +#define PIPEA_DATA_N2 0x6003c +#define PIPEA_DATA_N2_OFFSET 0 + +#define PIPEA_LINK_M1 0x60040 +#define PIPEA_LINK_M1_OFFSET 0 +#define PIPEA_LINK_N1 0x60044 +#define PIPEA_LINK_N1_OFFSET 0 + +#define PIPEA_LINK_M2 0x60048 +#define PIPEA_LINK_M2_OFFSET 0 +#define PIPEA_LINK_N2 0x6004c +#define PIPEA_LINK_N2_OFFSET 0 + +/* PIPEB timing regs are same start from 0x61000 */ + +#define PIPEB_DATA_M1 0x61030 +#define PIPEB_DATA_N1 0x61034 + +#define PIPEB_DATA_M2 0x61038 +#define PIPEB_DATA_N2 0x6103c + +#define PIPEB_LINK_M1 0x61040 +#define PIPEB_LINK_N1 0x61044 + +#define PIPEB_LINK_M2 0x61048 +#define PIPEB_LINK_N2 0x6104c + +/* PIPEC timing regs */ + +#define PIPEC_DATA_M1 0x62030 +#define PIPEC_DATA_N1 0x62034 + +#define PIPEC_DATA_M2 0x62038 +#define PIPEC_DATA_N2 0x6203c + +#define PIPEC_LINK_M1 0x62040 +#define PIPEC_LINK_N1 0x62044 + +#define PIPEC_LINK_M2 0x62048 +#define PIPEC_LINK_N2 0x6204c + +/* PIPECONF for pipe A/B addr is same */ + +/* cusor A is only connected to pipe A, + cursor B is connected to pipe B. Otherwise no change. */ + +/* Plane A/B, DSPACNTR/DSPBCNTR addr not changed */ + +/* CPU panel fitter */ +#define PFA_CTL_1 0x68080 +#define PFB_CTL_1 0x68880 +#define PFC_CTL_1 0x69080 +#define PF_ENABLE (1<<31) +#define PFA_CTL_2 0x68084 +#define PFB_CTL_2 0x68884 +#define PFC_CTL_2 0x69084 +#define PFA_CTL_3 0x68088 +#define PFB_CTL_3 0x68888 +#define PFC_CTL_3 0x69088 +#define PFA_CTL_4 0x68090 +#define PFB_CTL_4 0x68890 +#define PFC_CTL_4 0x69090 + +#define PFA_WIN_POS 0x68070 +#define PFB_WIN_POS 0x68870 +#define PFC_WIN_POS 0x69070 +#define PFA_WIN_SIZE 0x68074 +#define PFB_WIN_SIZE 0x68874 +#define PFC_WIN_SIZE 0x69074 + +/* legacy palette */ +#define LGC_PALETTE_A 0x4a000 +#define LGC_PALETTE_B 0x4a800 + +/* interrupts */ +#define DE_MASTER_IRQ_CONTROL (1 << 31) +#define DE_SPRITEB_FLIP_DONE (1 << 29) +#define DE_SPRITEA_FLIP_DONE (1 << 28) +#define DE_PLANEB_FLIP_DONE (1 << 27) +#define DE_PLANEA_FLIP_DONE (1 << 26) +#define DE_PCU_EVENT (1 << 25) +#define DE_GTT_FAULT (1 << 24) +#define DE_POISON (1 << 23) +#define DE_PERFORM_COUNTER (1 << 22) +#define DE_PCH_EVENT (1 << 21) +#define DE_AUX_CHANNEL_A (1 << 20) +#define DE_DP_A_HOTPLUG (1 << 19) +#define DE_GSE (1 << 18) +#define DE_PIPEB_VBLANK (1 << 15) +#define DE_PIPEB_EVEN_FIELD (1 << 14) +#define DE_PIPEB_ODD_FIELD (1 << 13) +#define DE_PIPEB_LINE_COMPARE (1 << 12) +#define DE_PIPEB_VSYNC (1 << 11) +#define DE_PIPEB_FIFO_UNDERRUN (1 << 8) +#define DE_PIPEA_VBLANK (1 << 7) +#define DE_PIPEA_EVEN_FIELD (1 << 6) +#define DE_PIPEA_ODD_FIELD (1 << 5) +#define DE_PIPEA_LINE_COMPARE (1 << 4) +#define DE_PIPEA_VSYNC (1 << 3) +#define DE_PIPEA_FIFO_UNDERRUN (1 << 0) + +#define DEISR 0x44000 +#define DEIMR 0x44004 +#define DEIIR 0x44008 +#define DEIER 0x4400c + +/* GT interrupt */ +#define GT_SYNC_STATUS (1 << 2) +#define GT_USER_INTERRUPT (1 << 0) + +#define GTISR 0x44010 +#define GTIMR 0x44014 +#define GTIIR 0x44018 +#define GTIER 0x4401c + +/* PCH */ + +/* south display engine interrupt */ +#define SDE_CRT_HOTPLUG (1 << 11) +#define SDE_PORTD_HOTPLUG (1 << 10) +#define SDE_PORTC_HOTPLUG (1 << 9) +#define SDE_PORTB_HOTPLUG (1 << 8) +#define SDE_SDVOB_HOTPLUG (1 << 6) + +#define SDEISR 0xc4000 +#define SDEIMR 0xc4004 +#define SDEIIR 0xc4008 +#define SDEIER 0xc400c + +/* digital port hotplug */ +#define PCH_PORT_HOTPLUG 0xc4030 +#define PORTD_HOTPLUG_ENABLE (1 << 20) +#define PORTD_PULSE_DURATION_2ms (0) +#define PORTD_PULSE_DURATION_4_5ms (1 << 18) +#define PORTD_PULSE_DURATION_6ms (2 << 18) +#define PORTD_PULSE_DURATION_100ms (3 << 18) +#define PORTD_HOTPLUG_NO_DETECT (0) +#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16) +#define PORTD_HOTPLUG_LONG_DETECT (1 << 17) +#define PORTC_HOTPLUG_ENABLE (1 << 12) +#define PORTC_PULSE_DURATION_2ms (0) +#define PORTC_PULSE_DURATION_4_5ms (1 << 10) +#define PORTC_PULSE_DURATION_6ms (2 << 10) +#define PORTC_PULSE_DURATION_100ms (3 << 10) +#define PORTC_HOTPLUG_NO_DETECT (0) +#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8) +#define PORTC_HOTPLUG_LONG_DETECT (1 << 9) +#define PORTB_HOTPLUG_ENABLE (1 << 4) +#define PORTB_PULSE_DURATION_2ms (0) +#define PORTB_PULSE_DURATION_4_5ms (1 << 2) +#define PORTB_PULSE_DURATION_6ms (2 << 2) +#define PORTB_PULSE_DURATION_100ms (3 << 2) +#define PORTB_HOTPLUG_NO_DETECT (0) +#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0) +#define PORTB_HOTPLUG_LONG_DETECT (1 << 1) + +#define PCH_GPIOA 0xc5010 +#define PCH_GPIOB 0xc5014 +#define PCH_GPIOC 0xc5018 +#define PCH_GPIOD 0xc501c +#define PCH_GPIOE 0xc5020 +#define PCH_GPIOF 0xc5024 +#define PCH_GMBUS0 0xc5100 +#define PCH_GMBUS1 0xc5104 +#define PCH_GMBUS2 0xc5108 +#define PCH_GMBUS3 0xc510c +#define PCH_GMBUS4 0xc5110 +#define PCH_GMBUS5 0xc5120 + +#define PCH_DPLL_A 0xc6014 +#define PCH_DPLL_B 0xc6018 + +#define PCH_FPA0 0xc6040 +#define PCH_FPA1 0xc6044 +#define PCH_FPB0 0xc6048 +#define PCH_FPB1 0xc604c + +#define PCH_DPLL_TEST 0xc606c + +#define PCH_DREF_CONTROL 0xC6200 +#define DREF_CONTROL_MASK 0x7fc3 +#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13) +#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13) +#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3<<13) +#define DREF_SSC_SOURCE_DISABLE (0<<11) +#define DREF_SSC_SOURCE_ENABLE (2<<11) +#define DREF_NONSPREAD_SOURCE_DISABLE (0<<9) +#define DREF_NONSPREAD_SOURCE_ENABLE (2<<9) +#define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7) +#define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7) +#define DREF_SSC4_DOWNSPREAD (0<<6) +#define DREF_SSC4_CENTERSPREAD (1<<6) +#define DREF_SSC1_DISABLE (0<<1) +#define DREF_SSC1_ENABLE (1<<1) +#define DREF_SSC4_DISABLE (0) +#define DREF_SSC4_ENABLE (1) + +#define PCH_RAWCLK_FREQ 0xc6204 +#define FDL_TP1_TIMER_SHIFT 12 +#define FDL_TP1_TIMER_MASK (3<<12) +#define FDL_TP2_TIMER_SHIFT 10 +#define FDL_TP2_TIMER_MASK (3<<10) +#define RAWCLK_FREQ_MASK 0x3ff + +#define PCH_DPLL_TMR_CFG 0xc6208 + +#define PCH_SSC4_PARMS 0xc6210 +#define PCH_SSC4_AUX_PARMS 0xc6214 + +/* CPT */ +#define PCH_DPLL_ANALOG_CTL 0xc6300 + +#define PCH_DPLL_SEL 0xc7000 +#define TRANSA_DPLL_ENABLE (1<<3) +#define TRANSA_DPLLA_SEL (0) +#define TRANSA_DPLLB_SEL (1<<0) +#define TRANSB_DPLL_ENABLE (1<<7) +#define TRANSB_DPLLA_SEL (0<<4) +#define TRANSB_DPLLB_SEL (1<<4) +#define TRANSC_DPLL_ENABLE (1<<11) +#define TRANSC_DPLLA_SEL (0<<8) +#define TRANSC_DPLLB_SEL (1<<8) + +/* transcoder */ + +#define TRANS_HTOTAL_A 0xe0000 +#define TRANS_HTOTAL_SHIFT 16 +#define TRANS_HACTIVE_SHIFT 0 +#define TRANS_HBLANK_A 0xe0004 +#define TRANS_HBLANK_END_SHIFT 16 +#define TRANS_HBLANK_START_SHIFT 0 +#define TRANS_HSYNC_A 0xe0008 +#define TRANS_HSYNC_END_SHIFT 16 +#define TRANS_HSYNC_START_SHIFT 0 +#define TRANS_VTOTAL_A 0xe000c +#define TRANS_VTOTAL_SHIFT 16 +#define TRANS_VACTIVE_SHIFT 0 +#define TRANS_VBLANK_A 0xe0010 +#define TRANS_VBLANK_END_SHIFT 16 +#define TRANS_VBLANK_START_SHIFT 0 +#define TRANS_VSYNC_A 0xe0014 +#define TRANS_VSYNC_END_SHIFT 16 +#define TRANS_VSYNC_START_SHIFT 0 +#define TRANS_VSYNCSHIFT_A 0xe0028 + +#define TRANSA_DATA_M1 0xe0030 +#define TRANSA_DATA_N1 0xe0034 +#define TRANSA_DATA_M2 0xe0038 +#define TRANSA_DATA_N2 0xe003c +#define TRANSA_DP_LINK_M1 0xe0040 +#define TRANSA_DP_LINK_N1 0xe0044 +#define TRANSA_DP_LINK_M2 0xe0048 +#define TRANSA_DP_LINK_N2 0xe004c + +#define TRANS_HTOTAL_B 0xe1000 +#define TRANS_HBLANK_B 0xe1004 +#define TRANS_HSYNC_B 0xe1008 +#define TRANS_VTOTAL_B 0xe100c +#define TRANS_VBLANK_B 0xe1010 +#define TRANS_VSYNC_B 0xe1014 +#define TRANS_VSYNCSHIFT_B 0xe1028 + +#define TRANSB_DATA_M1 0xe1030 +#define TRANSB_DATA_N1 0xe1034 +#define TRANSB_DATA_M2 0xe1038 +#define TRANSB_DATA_N2 0xe103c +#define TRANSB_DP_LINK_M1 0xe1040 +#define TRANSB_DP_LINK_N1 0xe1044 +#define TRANSB_DP_LINK_M2 0xe1048 +#define TRANSB_DP_LINK_N2 0xe104c + +#define TRANS_HTOTAL_C 0xe2000 +#define TRANS_HBLANK_C 0xe2004 +#define TRANS_HSYNC_C 0xe2008 +#define TRANS_VTOTAL_C 0xe200c +#define TRANS_VBLANK_C 0xe2010 +#define TRANS_VSYNC_C 0xe2014 +#define TRANS_VSYNCSHIFT_C 0xe2028 + +#define TRANSC_DATA_M1 0xe2030 +#define TRANSC_DATA_N1 0xe2034 +#define TRANSC_DATA_M2 0xe2038 +#define TRANSC_DATA_N2 0xe203c +#define TRANSC_DP_LINK_M1 0xe2040 +#define TRANSC_DP_LINK_N1 0xe2044 +#define TRANSC_DP_LINK_M2 0xe2048 +#define TRANSC_DP_LINK_N2 0xe204c + +#define TRANSACONF 0xf0008 +#define TRANSBCONF 0xf1008 +#define TRANSCCONF 0xf2008 +#define TRANS_DISABLE (0<<31) +#define TRANS_ENABLE (1<<31) +#define TRANS_STATE_MASK (1<<30) +#define TRANS_STATE_DISABLE (0<<30) +#define TRANS_STATE_ENABLE (1<<30) +#define TRANS_FSYNC_DELAY_HB1 (0<<27) +#define TRANS_FSYNC_DELAY_HB2 (1<<27) +#define TRANS_FSYNC_DELAY_HB3 (2<<27) +#define TRANS_FSYNC_DELAY_HB4 (3<<27) +#define TRANS_DP_AUDIO_ONLY (1<<26) +#define TRANS_DP_VIDEO_AUDIO (0<<26) +#define TRANS_PROGRESSIVE (0<<21) +#define TRANS_8BPC (0<<5) +#define TRANS_10BPC (1<<5) +#define TRANS_6BPC (2<<5) +#define TRANS_12BPC (3<<5) + +#define FDI_RXA_CHICKEN 0xc200c +#define FDI_RXB_CHICKEN 0xc2010 +#define FDI_RX_PHASE_SYNC_POINTER_ENABLE (1) + +/* CPU: FDI_TX */ +#define FDI_TXA_CTL 0x60100 +#define FDI_TXB_CTL 0x61100 +#define FDI_TXC_CTL 0x62100 +#define FDI_TX_DISABLE (0<<31) +#define FDI_TX_ENABLE (1<<31) +#define FDI_LINK_TRAIN_PATTERN_1 (0<<28) +#define FDI_LINK_TRAIN_PATTERN_2 (1<<28) +#define FDI_LINK_TRAIN_PATTERN_IDLE (2<<28) +#define FDI_LINK_TRAIN_NONE (3<<28) +#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0<<25) +#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1<<25) +#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2<<25) +#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3<<25) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3<<22) +/* ILK always use 400mV 0dB for voltage swing and pre-emphasis level. + SNB has different settings. */ +/* SNB A-stepping */ +#define FDI_LINK_TRAIN_400MV_0DB_SNB_A (0x38<<22) +#define FDI_LINK_TRAIN_400MV_6DB_SNB_A (0x02<<22) +#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01<<22) +#define FDI_LINK_TRAIN_800MV_0DB_SNB_A (0x0<<22) +/* SNB B-stepping */ +#define FDI_LINK_TRAIN_400MV_0DB_SNB_B (0x0<<22) +#define FDI_LINK_TRAIN_400MV_6DB_SNB_B (0x3a<<22) +#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39<<22) +#define FDI_LINK_TRAIN_800MV_0DB_SNB_B (0x38<<22) +#define FDI_LINK_TRAIN_VOL_EMP_MASK (0x3f<<22) +#define FDI_DP_PORT_WIDTH_X1 (0<<19) +#define FDI_DP_PORT_WIDTH_X2 (1<<19) +#define FDI_DP_PORT_WIDTH_X3 (2<<19) +#define FDI_DP_PORT_WIDTH_X4 (3<<19) +#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18) +/* Ironlake: hardwired to 1 */ +#define FDI_TX_PLL_ENABLE (1<<14) +/* both Tx and Rx */ +#define FDI_SCRAMBLING_ENABLE (0<<7) +#define FDI_SCRAMBLING_DISABLE (1<<7) + +/* FDI_RX, FDI_X is hard-wired to Transcoder_X */ +#define FDI_RXA_CTL 0xf000c +#define FDI_RXB_CTL 0xf100c +#define FDI_RXC_CTL 0xf200c +#define FDI_RX_ENABLE (1<<31) +#define FDI_RX_DISABLE (0<<31) +/* train, dp width same as FDI_TX */ +#define FDI_DP_PORT_WIDTH_X8 (7<<19) +#define FDI_8BPC (0<<16) +#define FDI_10BPC (1<<16) +#define FDI_6BPC (2<<16) +#define FDI_12BPC (3<<16) +#define FDI_LINK_REVERSE_OVERWRITE (1<<15) +#define FDI_DMI_LINK_REVERSE_MASK (1<<14) +#define FDI_RX_PLL_ENABLE (1<<13) +#define FDI_FS_ERR_CORRECT_ENABLE (1<<11) +#define FDI_FE_ERR_CORRECT_ENABLE (1<<10) +#define FDI_FS_ERR_REPORT_ENABLE (1<<9) +#define FDI_FE_ERR_REPORT_ENABLE (1<<8) +#define FDI_RX_ENHANCE_FRAME_ENABLE (1<<6) +#define FDI_SEL_RAWCLK (0<<4) +#define FDI_SEL_PCDCLK (1<<4) +/* CPT */ +#define FDI_AUTO_TRAINING (1<<10) +#define FDI_LINK_TRAIN_PATTERN_1_CPT (0<<8) +#define FDI_LINK_TRAIN_PATTERN_2_CPT (1<<8) +#define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2<<8) +#define FDI_LINK_TRAIN_NORMAL_CPT (3<<8) +#define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3<<8) + +#define FDI_RXA_MISC 0xf0010 +#define FDI_RXB_MISC 0xf1010 +#define FDI_RXC_MISC 0xf2010 +#define FDI_RXA_TUSIZE1 0xf0030 +#define FDI_RXA_TUSIZE2 0xf0038 +#define FDI_RXB_TUSIZE1 0xf1030 +#define FDI_RXB_TUSIZE2 0xf1038 +#define FDI_RXC_TUSIZE1 0xf2030 +#define FDI_RXC_TUSIZE2 0xf2038 + +/* FDI_RX interrupt register format */ +#define FDI_RX_INTER_LANE_ALIGN (1<<10) +#define FDI_RX_SYMBOL_LOCK (1<<9) /* train 2 */ +#define FDI_RX_BIT_LOCK (1<<8) /* train 1 */ +#define FDI_RX_TRAIN_PATTERN_2_FAIL (1<<7) +#define FDI_RX_FS_CODE_ERR (1<<6) +#define FDI_RX_FE_CODE_ERR (1<<5) +#define FDI_RX_SYMBOL_ERR_RATE_ABOVE (1<<4) +#define FDI_RX_HDCP_LINK_FAIL (1<<3) +#define FDI_RX_PIXEL_FIFO_OVERFLOW (1<<2) +#define FDI_RX_CROSS_CLOCK_OVERFLOW (1<<1) +#define FDI_RX_SYMBOL_QUEUE_OVERFLOW (1<<0) + +#define FDI_RXA_IIR 0xf0014 +#define FDI_RXA_IMR 0xf0018 +#define FDI_RXB_IIR 0xf1014 +#define FDI_RXB_IMR 0xf1018 + +#define FDI_PLL_CTL_1 0xfe000 +#define FDI_PLL_CTL_2 0xfe004 + +/* CRT */ +#define PCH_ADPA 0xe1100 +#define ADPA_TRANS_SELECT_MASK (1<<30) +#define ADPA_TRANS_A_SELECT 0 +#define ADPA_TRANS_B_SELECT (1<<30) +/* HPD is here */ +#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */ +#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24) +#define ADPA_CRT_HOTPLUG_ENABLE (1<<23) +#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22) +#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22) +#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21) +#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21) +#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20) +#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20) +#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18) +#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17) +#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17) +#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) +/* polarity control not changed */ + +/* or SDVOB */ +#define HDMIB 0xe1140 +#define PORT_ENABLE (1 << 31) +#define TRANSCODER_A (0) +#define TRANSCODER_B (1 << 30) +#define COLOR_FORMAT_8bpc (0) +#define COLOR_FORMAT_12bpc (3 << 26) +#define SDVOB_HOTPLUG_ENABLE (1 << 23) +#define SDVO_ENCODING (0) +#define TMDS_ENCODING (2 << 10) +#define NULL_PACKET_VSYNC_ENABLE (1 << 9) +#define SDVOB_BORDER_ENABLE (1 << 7) +#define AUDIO_ENABLE (1 << 6) +#define VSYNC_ACTIVE_HIGH (1 << 4) +#define HSYNC_ACTIVE_HIGH (1 << 3) +#define PORT_DETECTED (1 << 2) + +#define HDMIC 0xe1150 +#define HDMID 0xe1160 +#define PCH_LVDS 0xe1180 + +#define BLC_PWM_CPU_CTL2 0x48250 +#define PWM_ENABLE (1 << 31) +#define PWM_PIPE_A (0 << 29) +#define PWM_PIPE_B (1 << 29) +#define BLC_PWM_CPU_CTL 0x48254 + +#define BLC_PWM_PCH_CTL1 0xc8250 +#define PWM_PCH_ENABLE (1 << 31) +#define PWM_POLARITY_ACTIVE_LOW (1 << 29) +#define PWM_POLARITY_ACTIVE_HIGH (0 << 29) +#define PWM_POLARITY_ACTIVE_LOW2 (1 << 28) +#define PWM_POLARITY_ACTIVE_HIGH2 (0 << 28) + +#define BLC_PWM_PCH_CTL2 0xc8254 + +#define PCH_PP_STATUS 0xc7200 +#define PCH_PP_CONTROL 0xc7204 +#define EDP_FORCE_VDD (1 << 3) +#define EDP_BLC_ENABLE (1 << 2) +#define PANEL_POWER_RESET (1 << 1) +#define PANEL_POWER_OFF (0 << 0) +#define PANEL_POWER_ON (1 << 0) +#define PCH_PP_ON_DELAYS 0xc7208 +#define EDP_PANEL (1 << 30) +#define PCH_PP_OFF_DELAYS 0xc720c +#define PCH_PP_DIVISOR 0xc7210 + +#define AUD_CONFIG 0x62000 +#define AUD_DEBUG 0x62010 +#define AUD_VID_DID 0x62020 +#define AUD_RID 0x62024 +#define AUD_SUBN_CNT 0x62028 +#define AUD_FUNC_GRP 0x62040 +#define AUD_SUBN_CNT2 0x62044 +#define AUD_GRP_CAP 0x62048 +#define AUD_PWRST 0x6204c +#define AUD_SUPPWR 0x62050 +#define AUD_SID 0x62054 +#define AUD_OUT_CWCAP 0x62070 +#define AUD_OUT_PCMSIZE 0x62074 +#define AUD_OUT_STR 0x62078 +#define AUD_OUT_DIG_CNVT 0x6207c +#define AUD_OUT_CH_STR 0x62080 +#define AUD_OUT_STR_DESC 0x62084 +#define AUD_PINW_CAP 0x620a0 +#define AUD_PIN_CAP 0x620a4 +#define AUD_PINW_CONNLNG 0x620a8 +#define AUD_PINW_CONNLST 0x620ac +#define AUD_PINW_CNTR 0x620b0 +#define AUD_PINW_UNSOLRESP 0x620b8 +#define AUD_CNTL_ST 0x620b4 +#define AUD_PINW_CONFIG 0x620bc +#define AUD_HDMIW_STATUS 0x620d4 +#define AUD_HDMIW_HDMIEDID 0x6210c +#define AUD_HDMIW_INFOFR 0x62118 +#define AUD_CONV_CHCNT 0x62120 +#define AUD_CTS_ENABLE 0x62128 + +#define VIDEO_DIP_CTL 0x61170 +#define VIDEO_DIP_DATA 0x61178 + +/* CPT */ +#define TRANS_DP_CTL_A 0xe0300 +#define TRANS_DP_CTL_B 0xe1300 +#define TRANS_DP_CTL_C 0xe2300 +#define TRANS_DP_OUTPUT_ENABLE (1<<31) +#define TRANS_DP_PORT_SEL_B (0<<29) +#define TRANS_DP_PORT_SEL_C (1<<29) +#define TRANS_DP_PORT_SEL_D (2<<29) +#define TRANS_DP_PORT_SEL_MASK (3<<29) +#define TRANS_DP_AUDIO_ONLY (1<<26) +#define TRANS_DP_ENH_FRAMING (1<<18) +#define TRANS_DP_8BPC (0<<9) +#define TRANS_DP_10BPC (1<<9) +#define TRANS_DP_6BPC (2<<9) +#define TRANS_DP_12BPC (3<<9) +#define TRANS_DP_VSYNC_ACTIVE_HIGH (1<<4) +#define TRANS_DP_VSYNC_ACTIVE_LOW 0 +#define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3) +#define TRANS_DP_HSYNC_ACTIVE_LOW 0 + +/* Debug regs */ +#define GEN6_TD_CTL 0x7000 /* <= GEN5 was at 0x8000 */ +#define GEN6_TD_CTL_FORCE_TD_BKPT (1<<4) + +/* Port debugging + */ + +#define PORT_DBG 0x42308 +#define PORT_DBG_DRRS_HW_STATE_OFF (0<<30) +#define PORT_DBG_DRRS_HW_STATE_LOW (1<<30) +#define PORT_DBG_DRRS_HW_STATE_HIGH (2<<30) + +/* RC6 residence counters + */ +#define RC6_RESIDENCY_TIME 0x138108 +#define RC6p_RESIDENCY_TIME 0x13810C +#define RC6pp_RESIDENCY_TIME 0x138110 + +#define GEN6_RPNSWREQ 0xA008 +#define GEN6_RC_VIDEO_FREQ 0xA00C +#define GEN6_RC_CONTROL 0xA090 +#define GEN6_RP_DOWN_TIMEOUT 0xA010 +#define GEN6_RP_INTERRUPT_LIMITS 0xA014 +#define GEN6_RPSTAT1 0xA01C +#define GEN6_RP_CONTROL 0xA024 +#define GEN6_RP_UP_THRESHOLD 0xA02C +#define GEN6_RP_DOWN_THRESHOLD 0xA030 +#define GEN6_RP_CUR_UP_EI 0xA050 +#define GEN6_RP_CUR_UP 0xA054 +#define GEN6_RP_PREV_UP 0xA058 +#define GEN6_RP_CUR_DOWN_EI 0xA05C +#define GEN6_RP_CUR_DOWN 0xA060 +#define GEN6_RP_PREV_DOWN 0xA064 +#define GEN6_RP_UP_EI 0xA068 +#define GEN6_RP_DOWN_EI 0xA06C +#define GEN6_RP_IDLE_HYSTERSIS 0xA070 +#define GEN6_RC_STATE 0xA094 +#define GEN6_RC1_WAKE_RATE_LIMIT 0xA098 +#define GEN6_RC6_WAKE_RATE_LIMIT 0xA09C +#define GEN6_RC6pp_WAKE_RATE_LIMIT 0xA0A0 +#define GEN6_RC_EVALUATION_INTERVAL 0xA0A8 +#define GEN6_RC_IDLE_HYSTERSIS 0xA0AC +#define GEN6_RC_SLEEP 0xA0B0 +#define GEN6_RC1e_THRESHOLD 0xA0B4 +#define GEN6_RC6_THRESHOLD 0xA0B8 +#define GEN6_RC6p_THRESHOLD 0xA0BC +#define GEN6_RC6pp_THRESHOLD 0xA0C0 +#define GEN6_PMINTRMSK 0xA168 +#define GEN6_RC_EVALUATION_INTERVAL 0xA0A8 +#define GEN6_RC_IDLE_HYSTERSIS 0xA0AC +#define GEN6_PMIER 0x4402C +#define GEN6_PMIMR 0x44024 /* rps_lock */ +#define GEN6_PMINTRMSK 0xA168 + +/* Haswell-related items */ + +/* HSW Power Wells */ +#define HSW_PWR_WELL_CTL1 0x45400 /* BIOS */ +#define HSW_PWR_WELL_CTL2 0x45404 /* Driver */ +#define HSW_PWR_WELL_CTL3 0x45408 /* KVMR */ +#define HSW_PWR_WELL_CTL4 0x4540C /* Debug */ +#define HSW_PWR_WELL_ENABLE (1<<31) +#define HSW_PWR_WELL_STATE (1<<30) +#define HSW_PWR_WELL_CTL5 0x45410 +#define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1<<31) +#define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1<<20) +#define HSW_PWR_WELL_FORCE_ON (1<<19) +#define HSW_PWR_WELL_CTL6 0x45414 + +/* Per-pipe DDI Function Control */ +#define PIPE_DDI_FUNC_CTL_A 0x60400 +#define PIPE_DDI_FUNC_CTL_B 0x61400 +#define PIPE_DDI_FUNC_CTL_C 0x62400 +#define PIPE_DDI_FUNC_CTL_EDP 0x6F400 +#define DDI_FUNC_CTL(pipe) _PIPE(pipe, \ + PIPE_DDI_FUNC_CTL_A, \ + PIPE_DDI_FUNC_CTL_B) +#define PIPE_DDI_FUNC_ENABLE (1<<31) +/* Those bits are ignored by pipe EDP since it can only connect to DDI A */ +#define PIPE_DDI_PORT_MASK (0xf<<28) +#define PIPE_DDI_SELECT_PORT(x) ((x)<<28) +#define PIPE_DDI_MODE_SELECT_HDMI (0<<24) +#define PIPE_DDI_MODE_SELECT_DVI (1<<24) +#define PIPE_DDI_MODE_SELECT_DP_SST (2<<24) +#define PIPE_DDI_MODE_SELECT_DP_MST (3<<24) +#define PIPE_DDI_MODE_SELECT_FDI (4<<24) +#define PIPE_DDI_BPC_8 (0<<20) +#define PIPE_DDI_BPC_10 (1<<20) +#define PIPE_DDI_BPC_6 (2<<20) +#define PIPE_DDI_BPC_12 (3<<20) +#define PIPE_DDI_BFI_ENABLE (1<<4) +#define PIPE_DDI_PORT_WIDTH_X1 (0<<1) +#define PIPE_DDI_PORT_WIDTH_X2 (1<<1) +#define PIPE_DDI_PORT_WIDTH_X4 (3<<1) + +/* DisplayPort Transport Control */ +#define DP_TP_CTL_A 0x64040 +#define DP_TP_CTL_B 0x64140 +#define DP_TP_CTL_C 0x64240 +#define DP_TP_CTL_D 0x64340 +#define DP_TP_CTL_E 0x64440 +#define DP_TP_CTL_ENABLE (1<<31) +#define DP_TP_CTL_MODE_SST (0<<27) +#define DP_TP_CTL_MODE_MST (1<<27) +#define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1<<18) +#define DP_TP_CTL_FDI_AUTOTRAIN (1<<15) +#define DP_TP_CTL_LINK_TRAIN_MASK (7<<8) +#define DP_TP_CTL_LINK_TRAIN_PAT1 (0<<8) +#define DP_TP_CTL_LINK_TRAIN_PAT2 (1<<8) +#define DP_TP_CTL_LINK_TRAIN_NORMAL (3<<8) + +/* DisplayPort Transport Status */ +#define DP_TP_STATUS_A 0x64044 +#define DP_TP_STATUS_B 0x64144 +#define DP_TP_STATUS_C 0x64244 +#define DP_TP_STATUS_D 0x64344 +#define DP_TP_STATUS_E 0x64444 +#define DP_TP_STATUS_AUTOTRAIN_DONE (1<<12) + +/* DDI Buffer Control */ +#define DDI_BUF_CTL_A 0x64000 +#define DDI_BUF_CTL_B 0x64100 +#define DDI_BUF_CTL_C 0x64200 +#define DDI_BUF_CTL_D 0x64300 +#define DDI_BUF_CTL_E 0x64400 +#define DDI_BUF_CTL_ENABLE (1<<31) +#define DDI_BUF_EMP_400MV_0DB_HSW (0<<24) /* Sel0 */ +#define DDI_BUF_EMP_400MV_3_5DB_HSW (1<<24) /* Sel1 */ +#define DDI_BUF_EMP_400MV_6DB_HSW (2<<24) /* Sel2 */ +#define DDI_BUF_EMP_400MV_9_5DB_HSW (3<<24) /* Sel3 */ +#define DDI_BUF_EMP_600MV_0DB_HSW (4<<24) /* Sel4 */ +#define DDI_BUF_EMP_600MV_3_5DB_HSW (5<<24) /* Sel5 */ +#define DDI_BUF_EMP_600MV_6DB_HSW (6<<24) /* Sel6 */ +#define DDI_BUF_EMP_800MV_0DB_HSW (7<<24) /* Sel7 */ +#define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */ +#define DDI_BUF_EMP_MASK (0xf<<24) +#define DDI_BUF_IS_IDLE (1<<7) +#define DDI_PORT_WIDTH_X1 (0<<1) +#define DDI_PORT_WIDTH_X2 (1<<1) +#define DDI_PORT_WIDTH_X4 (3<<1) +#define DDI_INIT_DISPLAY_DETECTED (1<<0) + +/* LPT PIXCLK_GATE */ +#define PIXCLK_GATE 0xC6020 +#define PIXCLK_GATE_UNGATE 1<<0 +#define PIXCLK_GATE_GATE 0<<0 + +/* SPLL */ +#define SPLL_CTL 0x46020 +#define SPLL_PLL_ENABLE (1<<31) +#define SPLL_PLL_SCC (1<<28) +#define SPLL_PLL_NON_SCC (2<<28) +#define SPLL_PLL_FREQ_810MHz (0<<26) +#define SPLL_PLL_FREQ_1350MHz (1<<26) + +/* WRPLL */ +#define WRPLL_CTL1 0x46040 +#define WRPLL_CTL2 0x46060 +#define WRPLL_PLL_ENABLE (1<<31) +#define WRPLL_PLL_SELECT_SSC (0x01<<28) +#define WRPLL_PLL_SELECT_NON_SCC (0x02<<28) +#define WRPLL_PLL_SELECT_LCPLL_2700 (0x03<<28) +/* WRPLL divider programming */ +#define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0) +#define WRPLL_DIVIDER_POST(x) ((x)<<8) +#define WRPLL_DIVIDER_FEEDBACK(x) ((x)<<16) + +/* Port clock selection */ +#define PORT_CLK_SEL_A 0x46100 +#define PORT_CLK_SEL_B 0x46104 +#define PORT_CLK_SEL_C 0x46108 +#define PORT_CLK_SEL_D 0x4610C +#define PORT_CLK_SEL_E 0x46110 +#define PORT_CLK_SEL_LCPLL_2700 (0<<29) +#define PORT_CLK_SEL_LCPLL_1350 (1<<29) +#define PORT_CLK_SEL_LCPLL_810 (2<<29) +#define PORT_CLK_SEL_SPLL (3<<29) +#define PORT_CLK_SEL_WRPLL1 (4<<29) +#define PORT_CLK_SEL_WRPLL2 (5<<29) + +/* Pipe clock selection */ +#define PIPE_CLK_SEL_A 0x46140 +#define PIPE_CLK_SEL_B 0x46144 +#define PIPE_CLK_SEL_C 0x46148 +/* For each pipe, we need to select the corresponding port clock */ +#define PIPE_CLK_SEL_DISABLED (0x0<<29) +#define PIPE_CLK_SEL_PORT(x) ((x+1)<<29) + +/* LCPLL Control */ +#define LCPLL_CTL 0x130040 +#define LCPLL_PLL_DISABLE (1<<31) +#define LCPLL_PLL_LOCK (1<<30) +#define LCPLL_CD_CLOCK_DISABLE (1<<25) +#define LCPLL_CD2X_CLOCK_DISABLE (1<<23) + +/* Pipe WM_LINETIME - watermark line time */ +#define PIPE_WM_LINETIME_A 0x45270 +#define PIPE_WM_LINETIME_B 0x45274 +#define PIPE_WM_LINETIME_C 0x45278 +#define PIPE_WM_LINETIME_MASK (0x1ff) +#define PIPE_WM_LINETIME_TIME(x) ((x)) +#define PIPE_WM_LINETIME_IPS_LINETIME_MASK (0x1ff<<16) +#define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x)<<16) + +/* SFUSE_STRAP */ +#define SFUSE_STRAP 0xc2014 +#define SFUSE_STRAP_DDIB_DETECTED (1<<2) +#define SFUSE_STRAP_DDIC_DETECTED (1<<1) +#define SFUSE_STRAP_DDID_DETECTED (1<<0) + +/* Valleyview related items */ + +/* Valleyview DPIO registers */ +#define VLV_DISPLAY_BASE 0x180000 +#define DPIO_PKT 0x2100 +#define DPIO_RID (0 << 24) +#define DPIO_OP_WRITE (1 << 16) +#define DPIO_OP_READ (0 << 16) +#define DPIO_PORTID (0x12 << 8) +#define DPIO_BYTE (0xf << 4) +#define DPIO_BUSY (1 << 0) +#define DPIO_DATA 0x2104 +#define DPIO_REG 0x2108 + +#endif /* _I810_REG_H */ diff --git a/lib/intel_reg_map.c b/lib/intel_reg_map.c new file mode 100644 index 00000000..0c8d49c9 --- /dev/null +++ b/lib/intel_reg_map.c @@ -0,0 +1,179 @@ +/* + * Copyright 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <sys/types.h> +#include "intel_gpu_tools.h" + +static struct intel_register_range gen_bwcl_register_map[] = { + {0x00000000, 0x00000fff, INTEL_RANGE_RW}, + {0x00001000, 0x00000fff, INTEL_RANGE_RSVD}, + {0x00002000, 0x00000fff, INTEL_RANGE_RW}, + {0x00003000, 0x000001ff, INTEL_RANGE_RW}, + {0x00003200, 0x00000dff, INTEL_RANGE_RW}, + {0x00004000, 0x000003ff, INTEL_RANGE_RSVD}, + {0x00004400, 0x00000bff, INTEL_RANGE_RSVD}, + {0x00005000, 0x00000fff, INTEL_RANGE_RW}, + {0x00006000, 0x00000fff, INTEL_RANGE_RW}, + {0x00007000, 0x000003ff, INTEL_RANGE_RW}, + {0x00007400, 0x000014ff, INTEL_RANGE_RW}, + {0x00008900, 0x000006ff, INTEL_RANGE_RSVD}, + {0x00009000, 0x00000fff, INTEL_RANGE_RSVD}, + {0x0000a000, 0x00000fff, INTEL_RANGE_RW}, + {0x0000b000, 0x00004fff, INTEL_RANGE_RSVD}, + {0x00010000, 0x00003fff, INTEL_RANGE_RW}, + {0x00014000, 0x0001bfff, INTEL_RANGE_RSVD}, + {0x00030000, 0x0000ffff, INTEL_RANGE_RW}, + {0x00040000, 0x0001ffff, INTEL_RANGE_RSVD}, + {0x00060000, 0x0000ffff, INTEL_RANGE_RW}, + {0x00070000, 0x00002fff, INTEL_RANGE_RW}, + {0x00073000, 0x00000fff, INTEL_RANGE_RW}, + {0x00074000, 0x0000bfff, INTEL_RANGE_RSVD}, + {0x00000000, 0x00000000, INTEL_RANGE_END} +}; + +static struct intel_register_range gen4_register_map[] = { + {0x00000000, 0x00000fff, INTEL_RANGE_RW}, + {0x00001000, 0x00000fff, INTEL_RANGE_RSVD}, + {0x00002000, 0x00000fff, INTEL_RANGE_RW}, + {0x00003000, 0x000001ff, INTEL_RANGE_RW}, + {0x00003200, 0x00000dff, INTEL_RANGE_RW}, + {0x00004000, 0x000003ff, INTEL_RANGE_RW}, + {0x00004400, 0x00000bff, INTEL_RANGE_RW}, + {0x00005000, 0x00000fff, INTEL_RANGE_RW}, + {0x00006000, 0x00000fff, INTEL_RANGE_RW}, + {0x00007000, 0x000003ff, INTEL_RANGE_RW}, + {0x00007400, 0x000014ff, INTEL_RANGE_RW}, + {0x00008900, 0x000006ff, INTEL_RANGE_RSVD}, + {0x00009000, 0x00000fff, INTEL_RANGE_RSVD}, + {0x0000a000, 0x00000fff, INTEL_RANGE_RW}, + {0x0000b000, 0x00004fff, INTEL_RANGE_RSVD}, + {0x00010000, 0x00003fff, INTEL_RANGE_RW}, + {0x00014000, 0x0001bfff, INTEL_RANGE_RSVD}, + {0x00030000, 0x0000ffff, INTEL_RANGE_RW}, + {0x00040000, 0x0001ffff, INTEL_RANGE_RSVD}, + {0x00060000, 0x0000ffff, INTEL_RANGE_RW}, + {0x00070000, 0x00002fff, INTEL_RANGE_RW}, + {0x00073000, 0x00000fff, INTEL_RANGE_RW}, + {0x00074000, 0x0000bfff, INTEL_RANGE_RSVD}, + {0x00000000, 0x00000000, INTEL_RANGE_END} +}; + +/* The documentation is a little sketchy on these register ranges. */ +static struct intel_register_range gen6_gt_register_map[] = { + {0x00000000, 0x00000fff, INTEL_RANGE_RW}, + {0x00001000, 0x00000fff, INTEL_RANGE_RSVD}, + {0x00002000, 0x00000fff, INTEL_RANGE_RW}, + {0x00003000, 0x000001ff, INTEL_RANGE_RW}, + {0x00003200, 0x00000dff, INTEL_RANGE_RW}, + {0x00004000, 0x00000fff, INTEL_RANGE_RW}, + {0x00005000, 0x0000017f, INTEL_RANGE_RW}, + {0x00005180, 0x00000e7f, INTEL_RANGE_RW}, + {0x00006000, 0x00001fff, INTEL_RANGE_RW}, + {0x00008000, 0x000007ff, INTEL_RANGE_RW}, + {0x00008800, 0x000000ff, INTEL_RANGE_RSVD}, + {0x00008900, 0x000006ff, INTEL_RANGE_RW}, + {0x00009000, 0x00000fff, INTEL_RANGE_RSVD}, + {0x0000a000, 0x00000fff, INTEL_RANGE_RW}, + {0x0000b000, 0x00004fff, INTEL_RANGE_RSVD}, + {0x00010000, 0x00001fff, INTEL_RANGE_RW}, + {0x00012000, 0x000003ff, INTEL_RANGE_RW}, + {0x00012400, 0x00000bff, INTEL_RANGE_RW}, + {0x00013000, 0x00000fff, INTEL_RANGE_RW}, + {0x00014000, 0x00000fff, INTEL_RANGE_RW}, + {0x00015000, 0x0000cfff, INTEL_RANGE_RW}, + {0x00022000, 0x00000fff, INTEL_RANGE_RW}, + {0x00023000, 0x00000fff, INTEL_RANGE_RSVD}, + {0x00024000, 0x00000fff, INTEL_RANGE_RW}, + {0x00025000, 0x0000afff, INTEL_RANGE_RSVD}, + {0x00030000, 0x0000ffff, INTEL_RANGE_RW}, + {0x00040000, 0x0000ffff, INTEL_RANGE_RW}, + {0x00050000, 0x0000ffff, INTEL_RANGE_RW}, + {0x00060000, 0x0000ffff, INTEL_RANGE_RW}, + {0x00070000, 0x00003fff, INTEL_RANGE_RW}, + {0x00074000, 0x0008bfff, INTEL_RANGE_RSVD}, + {0x00100000, 0x00007fff, INTEL_RANGE_RW}, + {0x00108000, 0x00037fff, INTEL_RANGE_RSVD}, + {0x00140000, 0x0003ffff, INTEL_RANGE_RW}, + {0x00000000, 0x00000000, INTEL_RANGE_END} +}; + +struct intel_register_map +intel_get_register_map(uint32_t devid) +{ + struct intel_register_map map; + const int gen = intel_gen(devid); + + if (gen >= 6) { + map.map = gen6_gt_register_map; + map.top = 0x180000; + } else if (IS_BROADWATER(devid) || IS_CRESTLINE(devid)) { + map.map = gen_bwcl_register_map; + map.top = 0x80000; + } else if (gen >= 4) { + map.map = gen4_register_map; + map.top = 0x80000; + } else { + fprintf(stderr, "Gen2/3 Ranges are not supported. Please use " + "unsafe access."); + abort(); + } + + map.alignment_mask = 0x3; + + return map; +} + +struct intel_register_range * +intel_get_register_range(struct intel_register_map map, uint32_t offset, int mode) +{ + struct intel_register_range *range = map.map; + uint32_t align = map.alignment_mask; + + if (offset & map.alignment_mask) + return NULL; + + if (offset >= map.top) + return NULL; + + while (!(range->flags & INTEL_RANGE_END)) { + /* list is assumed to be in order */ + if (offset < range->base) + break; + + if ( (offset >= range->base) && + (offset + align) <= (range->base + range->size)) { + if ((mode & range->flags) == mode) + return range; + } + range++; + } + + return NULL; +} diff --git a/lib/rendercopy.h b/lib/rendercopy.h new file mode 100644 index 00000000..5989d503 --- /dev/null +++ b/lib/rendercopy.h @@ -0,0 +1,81 @@ +#include <stdlib.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <getopt.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +struct scratch_buf { + drm_intel_bo *bo; + uint32_t stride; + uint32_t tiling; + uint32_t *data; + uint32_t *cpu_mapping; + uint32_t size; + unsigned num_tiles; +}; + +static inline void emit_vertex_2s(struct intel_batchbuffer *batch, + int16_t x, int16_t y) +{ + OUT_BATCH((uint16_t)y << 16 | (uint16_t)x); +} + +static inline void emit_vertex(struct intel_batchbuffer *batch, + float f) +{ + union { float f; uint32_t ui; } u; + u.f = f; + OUT_BATCH(u.ui); +} + +static inline void emit_vertex_normalized(struct intel_batchbuffer *batch, + float f, float total) +{ + union { float f; uint32_t ui; } u; + u.f = f / total; + OUT_BATCH(u.ui); +} + +static inline unsigned buf_width(struct scratch_buf *buf) +{ + return buf->stride/sizeof(uint32_t); +} + +static inline unsigned buf_height(struct scratch_buf *buf) +{ + return buf->size/buf->stride; +} + +typedef void (*render_copyfunc_t)(struct intel_batchbuffer *batch, + struct scratch_buf *src, unsigned src_x, unsigned src_y, + unsigned width, unsigned height, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y); + +void gen7_render_copyfunc(struct intel_batchbuffer *batch, + struct scratch_buf *src, unsigned src_x, unsigned src_y, + unsigned width, unsigned height, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y); +void gen6_render_copyfunc(struct intel_batchbuffer *batch, + struct scratch_buf *src, unsigned src_x, unsigned src_y, + unsigned width, unsigned height, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y); +void gen3_render_copyfunc(struct intel_batchbuffer *batch, + struct scratch_buf *src, unsigned src_x, unsigned src_y, + unsigned width, unsigned height, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y); +void gen2_render_copyfunc(struct intel_batchbuffer *batch, + struct scratch_buf *src, unsigned src_x, unsigned src_y, + unsigned width, unsigned height, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y); diff --git a/lib/rendercopy_gen6.c b/lib/rendercopy_gen6.c new file mode 100644 index 00000000..dafee88a --- /dev/null +++ b/lib/rendercopy_gen6.c @@ -0,0 +1,599 @@ +#include "rendercopy.h" +#include "gen6_render.h" + +#include <assert.h> + +#define ALIGN(x, y) (((x) + (y)-1) & ~((y)-1)) +#define VERTEX_SIZE (3*4) + +static const uint32_t ps_kernel_nomask_affine[][4] = { + { 0x0060005a, 0x204077be, 0x000000c0, 0x008d0040 }, + { 0x0060005a, 0x206077be, 0x000000c0, 0x008d0080 }, + { 0x0060005a, 0x208077be, 0x000000d0, 0x008d0040 }, + { 0x0060005a, 0x20a077be, 0x000000d0, 0x008d0080 }, + { 0x00000201, 0x20080061, 0x00000000, 0x00000000 }, + { 0x00600001, 0x20200022, 0x008d0000, 0x00000000 }, + { 0x02800031, 0x21c01cc9, 0x00000020, 0x0a8a0001 }, + { 0x00600001, 0x204003be, 0x008d01c0, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d01e0, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d0200, 0x00000000 }, + { 0x00600001, 0x20a003be, 0x008d0220, 0x00000000 }, + { 0x00600001, 0x20c003be, 0x008d0240, 0x00000000 }, + { 0x00600001, 0x20e003be, 0x008d0260, 0x00000000 }, + { 0x00600001, 0x210003be, 0x008d0280, 0x00000000 }, + { 0x00600001, 0x212003be, 0x008d02a0, 0x00000000 }, + { 0x05800031, 0x24001cc8, 0x00000040, 0x90019000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static uint32_t +batch_used(struct intel_batchbuffer *batch) +{ + return batch->ptr - batch->buffer; +} + +static uint32_t +batch_align(struct intel_batchbuffer *batch, uint32_t align) +{ + uint32_t offset = batch_used(batch); + offset = ALIGN(offset, align); + batch->ptr = batch->buffer + offset; + return offset; +} + +static uint32_t +batch_round_upto(struct intel_batchbuffer *batch, uint32_t divisor) +{ + uint32_t offset = batch_used(batch); + offset = (offset + divisor-1) / divisor * divisor; + batch->ptr = batch->buffer + offset; + return offset; +} + +static void * +batch_alloc(struct intel_batchbuffer *batch, uint32_t size, uint32_t align) +{ + uint32_t offset = batch_align(batch, align); + batch->ptr += size; + return memset(batch->buffer + offset, 0, size); +} + +static uint32_t +batch_offset(struct intel_batchbuffer *batch, void *ptr) +{ + return (uint8_t *)ptr - batch->buffer; +} + +static uint32_t +batch_copy(struct intel_batchbuffer *batch, const void *ptr, uint32_t size, uint32_t align) +{ + return batch_offset(batch, memcpy(batch_alloc(batch, size, align), ptr, size)); +} + +static void +gen6_render_flush(struct intel_batchbuffer *batch, uint32_t batch_end) +{ + int ret; + + ret = drm_intel_bo_subdata(batch->bo, 0, 4096, batch->buffer); + if (ret == 0) + ret = drm_intel_bo_mrb_exec(batch->bo, batch_end, + NULL, 0, 0, 0); + assert(ret == 0); +} + +static uint32_t +gen6_bind_buf(struct intel_batchbuffer *batch, struct scratch_buf *buf, + uint32_t format, int is_dst) +{ + struct gen6_surface_state *ss; + uint32_t write_domain, read_domain; + int ret; + + if (is_dst) { + write_domain = read_domain = I915_GEM_DOMAIN_RENDER; + } else { + write_domain = 0; + read_domain = I915_GEM_DOMAIN_SAMPLER; + } + + ss = batch_alloc(batch, sizeof(*ss), 32); + ss->ss0.surface_type = GEN6_SURFACE_2D; + ss->ss0.surface_format = format; + + ss->ss0.data_return_format = GEN6_SURFACERETURNFORMAT_FLOAT32; + ss->ss0.color_blend = 1; + ss->ss1.base_addr = buf->bo->offset; + + ret = drm_intel_bo_emit_reloc(batch->bo, + batch_offset(batch, ss) + 4, + buf->bo, 0, + read_domain, write_domain); + assert(ret == 0); + + ss->ss2.height = buf_height(buf) - 1; + ss->ss2.width = buf_width(buf) - 1; + ss->ss3.pitch = buf->stride - 1; + ss->ss3.tiled_surface = buf->tiling != I915_TILING_NONE; + ss->ss3.tile_walk = buf->tiling == I915_TILING_Y; + + return batch_offset(batch, ss); +} + +static uint32_t +gen6_bind_surfaces(struct intel_batchbuffer *batch, + struct scratch_buf *src, + struct scratch_buf *dst) +{ + uint32_t *binding_table; + + binding_table = batch_alloc(batch, 32, 32); + + binding_table[0] = + gen6_bind_buf(batch, dst, GEN6_SURFACEFORMAT_B8G8R8A8_UNORM, 1); + binding_table[1] = + gen6_bind_buf(batch, src, GEN6_SURFACEFORMAT_B8G8R8A8_UNORM, 0); + + return batch_offset(batch, binding_table); +} + +static void +gen6_emit_sip(struct intel_batchbuffer *batch) +{ + OUT_BATCH(GEN6_STATE_SIP | 0); + OUT_BATCH(0); +} + +static void +gen6_emit_urb(struct intel_batchbuffer *batch) +{ + OUT_BATCH(GEN6_3DSTATE_URB | (3 - 2)); + OUT_BATCH((1 - 1) << GEN6_3DSTATE_URB_VS_SIZE_SHIFT | + 24 << GEN6_3DSTATE_URB_VS_ENTRIES_SHIFT); /* at least 24 on GEN6 */ + OUT_BATCH(0 << GEN6_3DSTATE_URB_GS_SIZE_SHIFT | + 0 << GEN6_3DSTATE_URB_GS_ENTRIES_SHIFT); /* no GS thread */ +} + +static void +gen6_emit_state_base_address(struct intel_batchbuffer *batch) +{ + OUT_BATCH(GEN6_STATE_BASE_ADDRESS | (10 - 2)); + OUT_BATCH(0); /* general */ + OUT_RELOC(batch->bo, /* surface */ + I915_GEM_DOMAIN_INSTRUCTION, 0, + BASE_ADDRESS_MODIFY); + OUT_RELOC(batch->bo, /* instruction */ + I915_GEM_DOMAIN_INSTRUCTION, 0, + BASE_ADDRESS_MODIFY); + OUT_BATCH(0); /* indirect */ + OUT_RELOC(batch->bo, /* dynamic */ + I915_GEM_DOMAIN_INSTRUCTION, 0, + BASE_ADDRESS_MODIFY); + + /* upper bounds, disable */ + OUT_BATCH(0); + OUT_BATCH(BASE_ADDRESS_MODIFY); + OUT_BATCH(0); + OUT_BATCH(BASE_ADDRESS_MODIFY); +} + +static void +gen6_emit_viewports(struct intel_batchbuffer *batch, uint32_t cc_vp) +{ + OUT_BATCH(GEN6_3DSTATE_VIEWPORT_STATE_POINTERS | + GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CC | + (4 - 2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(cc_vp); +} + +static void +gen6_emit_vs(struct intel_batchbuffer *batch) +{ + /* disable VS constant buffer */ + OUT_BATCH(GEN6_3DSTATE_CONSTANT_VS | (5 - 2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN6_3DSTATE_VS | (6 - 2)); + OUT_BATCH(0); /* no VS kernel */ + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); /* pass-through */ +} + +static void +gen6_emit_gs(struct intel_batchbuffer *batch) +{ + /* disable GS constant buffer */ + OUT_BATCH(GEN6_3DSTATE_CONSTANT_GS | (5 - 2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN6_3DSTATE_GS | (7 - 2)); + OUT_BATCH(0); /* no GS kernel */ + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); /* pass-through */ +} + +static void +gen6_emit_clip(struct intel_batchbuffer *batch) +{ + OUT_BATCH(GEN6_3DSTATE_CLIP | (4 - 2)); + OUT_BATCH(0); + OUT_BATCH(0); /* pass-through */ + OUT_BATCH(0); +} + +static void +gen6_emit_wm_constants(struct intel_batchbuffer *batch) +{ + /* disable WM constant buffer */ + OUT_BATCH(GEN6_3DSTATE_CONSTANT_PS | (5 - 2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); +} + +static void +gen6_emit_null_depth_buffer(struct intel_batchbuffer *batch) +{ + OUT_BATCH(GEN6_3DSTATE_DEPTH_BUFFER | (7 - 2)); + OUT_BATCH(GEN6_SURFACE_NULL << GEN6_3DSTATE_DEPTH_BUFFER_TYPE_SHIFT | + GEN6_DEPTHFORMAT_D32_FLOAT << GEN6_3DSTATE_DEPTH_BUFFER_FORMAT_SHIFT); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN6_3DSTATE_CLEAR_PARAMS | (2 - 2)); + OUT_BATCH(0); +} + +static void +gen6_emit_invariant(struct intel_batchbuffer *batch) +{ + OUT_BATCH(GEN6_PIPELINE_SELECT | PIPELINE_SELECT_3D); + + OUT_BATCH(GEN6_3DSTATE_MULTISAMPLE | (3 - 2)); + OUT_BATCH(GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_CENTER | + GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_1); /* 1 sample/pixel */ + OUT_BATCH(0); + + OUT_BATCH(GEN6_3DSTATE_SAMPLE_MASK | (2 - 2)); + OUT_BATCH(1); +} + +static void +gen6_emit_cc(struct intel_batchbuffer *batch, uint32_t blend) +{ + OUT_BATCH(GEN6_3DSTATE_CC_STATE_POINTERS | (4 - 2)); + OUT_BATCH(blend | 1); + OUT_BATCH(1024 | 1); + OUT_BATCH(1024 | 1); +} + +static void +gen6_emit_sampler(struct intel_batchbuffer *batch, uint32_t state) +{ + OUT_BATCH(GEN6_3DSTATE_SAMPLER_STATE_POINTERS | + GEN6_3DSTATE_SAMPLER_STATE_MODIFY_PS | + (4 - 2)); + OUT_BATCH(0); /* VS */ + OUT_BATCH(0); /* GS */ + OUT_BATCH(state); +} + +static void +gen6_emit_sf(struct intel_batchbuffer *batch) +{ + OUT_BATCH(GEN6_3DSTATE_SF | (20 - 2)); + OUT_BATCH(1 << GEN6_3DSTATE_SF_NUM_OUTPUTS_SHIFT | + 1 << GEN6_3DSTATE_SF_URB_ENTRY_READ_LENGTH_SHIFT | + 1 << GEN6_3DSTATE_SF_URB_ENTRY_READ_OFFSET_SHIFT); + OUT_BATCH(0); + OUT_BATCH(GEN6_3DSTATE_SF_CULL_NONE); + OUT_BATCH(2 << GEN6_3DSTATE_SF_TRIFAN_PROVOKE_SHIFT); /* DW4 */ + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); /* DW9 */ + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); /* DW14 */ + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); /* DW19 */ +} + +static void +gen6_emit_wm(struct intel_batchbuffer *batch, int kernel) +{ + OUT_BATCH(GEN6_3DSTATE_WM | (9 - 2)); + OUT_BATCH(kernel); + OUT_BATCH(1 << GEN6_3DSTATE_WM_SAMPLER_COUNT_SHIFT | + 2 << GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT); + OUT_BATCH(0); + OUT_BATCH(6 << GEN6_3DSTATE_WM_DISPATCH_START_GRF_0_SHIFT); /* DW4 */ + OUT_BATCH((40 - 1) << GEN6_3DSTATE_WM_MAX_THREADS_SHIFT | + GEN6_3DSTATE_WM_DISPATCH_ENABLE | + GEN6_3DSTATE_WM_16_DISPATCH_ENABLE); + OUT_BATCH(1 << GEN6_3DSTATE_WM_NUM_SF_OUTPUTS_SHIFT | + GEN6_3DSTATE_WM_PERSPECTIVE_PIXEL_BARYCENTRIC); + OUT_BATCH(0); + OUT_BATCH(0); +} + +static void +gen6_emit_binding_table(struct intel_batchbuffer *batch, uint32_t wm_table) +{ + OUT_BATCH(GEN6_3DSTATE_BINDING_TABLE_POINTERS | + GEN6_3DSTATE_BINDING_TABLE_MODIFY_PS | + (4 - 2)); + OUT_BATCH(0); /* vs */ + OUT_BATCH(0); /* gs */ + OUT_BATCH(wm_table); +} + +static void +gen6_emit_drawing_rectangle(struct intel_batchbuffer *batch, struct scratch_buf *dst) +{ + OUT_BATCH(GEN6_3DSTATE_DRAWING_RECTANGLE | (4 - 2)); + OUT_BATCH(0); + OUT_BATCH((buf_height(dst) - 1) << 16 | (buf_width(dst) - 1)); + OUT_BATCH(0); +} + +static void +gen6_emit_vertex_elements(struct intel_batchbuffer *batch) +{ + /* The VUE layout + * dword 0-3: pad (0.0, 0.0, 0.0. 0.0) + * dword 4-7: position (x, y, 1.0, 1.0), + * dword 8-11: texture coordinate 0 (u0, v0, 0, 0) + * + * dword 4-11 are fetched from vertex buffer + */ + OUT_BATCH(GEN6_3DSTATE_VERTEX_ELEMENTS | (2 * 3 + 1 - 2)); + + OUT_BATCH(0 << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID | + GEN6_SURFACEFORMAT_R32G32B32A32_FLOAT << VE0_FORMAT_SHIFT | + 0 << VE0_OFFSET_SHIFT); + OUT_BATCH(GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_0_SHIFT | + GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_1_SHIFT | + GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT | + GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_3_SHIFT); + + /* x,y */ + OUT_BATCH(0 << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID | + GEN6_SURFACEFORMAT_R16G16_SSCALED << VE0_FORMAT_SHIFT | + 0 << VE0_OFFSET_SHIFT); /* offsets vb in bytes */ + OUT_BATCH(GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT | + GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT | + GEN6_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT | + GEN6_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT); + + /* u0, v0 */ + OUT_BATCH(0 << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID | + GEN6_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT | + 4 << VE0_OFFSET_SHIFT); /* offset vb in bytes */ + OUT_BATCH(GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT | + GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT | + GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT | + GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_3_SHIFT); +} + +static uint32_t +gen6_create_cc_viewport(struct intel_batchbuffer *batch) +{ + struct gen6_cc_viewport *vp; + + vp = batch_alloc(batch, sizeof(*vp), 32); + + vp->min_depth = -1.e35; + vp->max_depth = 1.e35; + + return batch_offset(batch, vp); +} + +static uint32_t +gen6_create_cc_blend(struct intel_batchbuffer *batch) +{ + struct gen6_blend_state *blend; + + blend = batch_alloc(batch, sizeof(*blend), 64); + + blend->blend0.dest_blend_factor = GEN6_BLENDFACTOR_ZERO; + blend->blend0.source_blend_factor = GEN6_BLENDFACTOR_ONE; + blend->blend0.blend_func = GEN6_BLENDFUNCTION_ADD; + blend->blend0.blend_enable = 1; + + blend->blend1.post_blend_clamp_enable = 1; + blend->blend1.pre_blend_clamp_enable = 1; + + return batch_offset(batch, blend); +} + +static uint32_t +gen6_create_kernel(struct intel_batchbuffer *batch) +{ + return batch_copy(batch, ps_kernel_nomask_affine, + sizeof(ps_kernel_nomask_affine), + 64); +} + +static uint32_t +gen6_create_sampler(struct intel_batchbuffer *batch, + sampler_filter_t filter, + sampler_extend_t extend) +{ + struct gen6_sampler_state *ss; + + ss = batch_alloc(batch, sizeof(*ss), 32); + ss->ss0.lod_preclamp = 1; /* GL mode */ + + /* We use the legacy mode to get the semantics specified by + * the Render extension. */ + ss->ss0.border_color_mode = GEN6_BORDER_COLOR_MODE_LEGACY; + + switch (filter) { + default: + case SAMPLER_FILTER_NEAREST: + ss->ss0.min_filter = GEN6_MAPFILTER_NEAREST; + ss->ss0.mag_filter = GEN6_MAPFILTER_NEAREST; + break; + case SAMPLER_FILTER_BILINEAR: + ss->ss0.min_filter = GEN6_MAPFILTER_LINEAR; + ss->ss0.mag_filter = GEN6_MAPFILTER_LINEAR; + break; + } + + switch (extend) { + default: + case SAMPLER_EXTEND_NONE: + ss->ss1.r_wrap_mode = GEN6_TEXCOORDMODE_CLAMP_BORDER; + ss->ss1.s_wrap_mode = GEN6_TEXCOORDMODE_CLAMP_BORDER; + ss->ss1.t_wrap_mode = GEN6_TEXCOORDMODE_CLAMP_BORDER; + break; + case SAMPLER_EXTEND_REPEAT: + ss->ss1.r_wrap_mode = GEN6_TEXCOORDMODE_WRAP; + ss->ss1.s_wrap_mode = GEN6_TEXCOORDMODE_WRAP; + ss->ss1.t_wrap_mode = GEN6_TEXCOORDMODE_WRAP; + break; + case SAMPLER_EXTEND_PAD: + ss->ss1.r_wrap_mode = GEN6_TEXCOORDMODE_CLAMP; + ss->ss1.s_wrap_mode = GEN6_TEXCOORDMODE_CLAMP; + ss->ss1.t_wrap_mode = GEN6_TEXCOORDMODE_CLAMP; + break; + case SAMPLER_EXTEND_REFLECT: + ss->ss1.r_wrap_mode = GEN6_TEXCOORDMODE_MIRROR; + ss->ss1.s_wrap_mode = GEN6_TEXCOORDMODE_MIRROR; + ss->ss1.t_wrap_mode = GEN6_TEXCOORDMODE_MIRROR; + break; + } + + return batch_offset(batch, ss); +} + +static void gen6_emit_vertex_buffer(struct intel_batchbuffer *batch) +{ + OUT_BATCH(GEN6_3DSTATE_VERTEX_BUFFERS | 3); + OUT_BATCH(VB0_VERTEXDATA | + 0 << VB0_BUFFER_INDEX_SHIFT | + VERTEX_SIZE << VB0_BUFFER_PITCH_SHIFT); + OUT_RELOC(batch->bo, I915_GEM_DOMAIN_VERTEX, 0, 0); + OUT_RELOC(batch->bo, I915_GEM_DOMAIN_VERTEX, 0, batch->bo->size-1); + OUT_BATCH(0); +} + +static uint32_t gen6_emit_primitive(struct intel_batchbuffer *batch) +{ + uint32_t offset; + + OUT_BATCH(GEN6_3DPRIMITIVE | + GEN6_3DPRIMITIVE_VERTEX_SEQUENTIAL | + _3DPRIM_RECTLIST << GEN6_3DPRIMITIVE_TOPOLOGY_SHIFT | + 0 << 9 | + 4); + OUT_BATCH(3); /* vertex count */ + offset = batch_used(batch); + OUT_BATCH(0); /* vertex_index */ + OUT_BATCH(1); /* single instance */ + OUT_BATCH(0); /* start instance location */ + OUT_BATCH(0); /* index buffer offset, ignored */ + + return offset; +} + +void gen6_render_copyfunc(struct intel_batchbuffer *batch, + struct scratch_buf *src, unsigned src_x, unsigned src_y, + unsigned width, unsigned height, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y) +{ + uint32_t wm_state, wm_kernel, wm_table; + uint32_t cc_vp, cc_blend, offset; + uint32_t batch_end; + + intel_batchbuffer_flush(batch); + + batch->ptr = batch->buffer + 1024; + batch_alloc(batch, 64, 64); + wm_table = gen6_bind_surfaces(batch, src, dst); + wm_kernel = gen6_create_kernel(batch); + wm_state = gen6_create_sampler(batch, + SAMPLER_FILTER_NEAREST, + SAMPLER_EXTEND_NONE); + + cc_vp = gen6_create_cc_viewport(batch); + cc_blend = gen6_create_cc_blend(batch); + + batch->ptr = batch->buffer; + + gen6_emit_invariant(batch); + gen6_emit_state_base_address(batch); + + gen6_emit_sip(batch); + gen6_emit_urb(batch); + + gen6_emit_viewports(batch, cc_vp); + gen6_emit_vs(batch); + gen6_emit_gs(batch); + gen6_emit_clip(batch); + gen6_emit_wm_constants(batch); + gen6_emit_null_depth_buffer(batch); + + gen6_emit_drawing_rectangle(batch, dst); + gen6_emit_cc(batch, cc_blend); + gen6_emit_sampler(batch, wm_state); + gen6_emit_sf(batch); + gen6_emit_wm(batch, wm_kernel); + gen6_emit_vertex_elements(batch); + gen6_emit_binding_table(batch, wm_table); + + gen6_emit_vertex_buffer(batch); + offset = gen6_emit_primitive(batch); + + OUT_BATCH(MI_BATCH_BUFFER_END); + batch_end = batch_align(batch, 8); + + *(uint32_t*)(batch->buffer + offset) = + batch_round_upto(batch, VERTEX_SIZE)/VERTEX_SIZE; + + emit_vertex_2s(batch, dst_x + width, dst_y + height); + emit_vertex_normalized(batch, src_x + width, buf_width(src)); + emit_vertex_normalized(batch, src_y + height, buf_height(src)); + + emit_vertex_2s(batch, dst_x, dst_y + height); + emit_vertex_normalized(batch, src_x, buf_width(src)); + emit_vertex_normalized(batch, src_y + height, buf_height(src)); + + emit_vertex_2s(batch, dst_x, dst_y); + emit_vertex_normalized(batch, src_x, buf_width(src)); + emit_vertex_normalized(batch, src_y, buf_height(src)); + + gen6_render_flush(batch, batch_end); + intel_batchbuffer_reset(batch); +} diff --git a/lib/rendercopy_gen7.c b/lib/rendercopy_gen7.c new file mode 100644 index 00000000..56181abf --- /dev/null +++ b/lib/rendercopy_gen7.c @@ -0,0 +1,801 @@ +#include "rendercopy.h" +#include "gen7_render.h" + +#include <assert.h> + +#define ALIGN(x, y) (((x) + (y)-1) & ~((y)-1)) +#define VERTEX_SIZE (3*4) + +#if DEBUG_RENDERCPY +static void dump_batch(struct intel_batchbuffer *batch) +#else +#define dump_batch(x) do { } while(0) +#endif + +struct { + uint32_t cc_state; + uint32_t blend_state; + uint32_t ds_state; +} cc; + +struct { + uint32_t cc_state; + uint32_t sf_clip_state; +} viewport; + +/* see shaders/ps/blit.g7a */ +static const uint32_t ps_kernel[][4] = { +#if 1 + { 0x0060005a, 0x214077bd, 0x000000c0, 0x008d0040 }, + { 0x0060005a, 0x216077bd, 0x000000c0, 0x008d0080 }, + { 0x0060005a, 0x218077bd, 0x000000d0, 0x008d0040 }, + { 0x0060005a, 0x21a077bd, 0x000000d0, 0x008d0080 }, + { 0x02800031, 0x2e001e3d, 0x00000140, 0x08840001 }, + { 0x05800031, 0x20001e3c, 0x00000e00, 0x90031000 }, + +#else + /* Write all -1 */ + { 0x00600001, 0x2e000061, 0x00000000, 0x3f800000 }, + { 0x00600001, 0x2e200061, 0x00000000, 0x3f800000 }, + { 0x00600001, 0x2e400061, 0x00000000, 0x3f800000 }, + { 0x00600001, 0x2e600061, 0x00000000, 0x3f800000 }, + { 0x00600001, 0x2e800061, 0x00000000, 0x3f800000 }, + { 0x00600001, 0x2ea00061, 0x00000000, 0x3f800000 }, + { 0x00600001, 0x2ec00061, 0x00000000, 0x3f800000 }, + { 0x00600001, 0x2ee00061, 0x00000000, 0x3f800000 }, + { 0x05800031, 0x20001e3c, 0x00000e00, 0x90031000 }, +#endif +}; + +static uint32_t +batch_used(struct intel_batchbuffer *batch) +{ + return batch->ptr - batch->buffer; +} + +static uint32_t +batch_align(struct intel_batchbuffer *batch, uint32_t align) +{ + uint32_t offset = batch_used(batch); + offset = ALIGN(offset, align); + batch->ptr = batch->buffer + offset; + return offset; +} + +static void * +batch_alloc(struct intel_batchbuffer *batch, uint32_t size, uint32_t align) +{ + uint32_t offset = batch_align(batch, align); + batch->ptr += size; + return memset(batch->buffer + offset, 0, size); +} + +static uint32_t +batch_offset(struct intel_batchbuffer *batch, void *ptr) +{ + return (uint8_t *)ptr - batch->buffer; +} + +static uint32_t +batch_copy(struct intel_batchbuffer *batch, const void *ptr, uint32_t size, uint32_t align) +{ + return batch_offset(batch, memcpy(batch_alloc(batch, size, align), ptr, size)); +} + +static void +gen6_render_flush(struct intel_batchbuffer *batch, uint32_t batch_end) +{ + int ret; + + ret = drm_intel_bo_subdata(batch->bo, 0, 4096, batch->buffer); + if (ret == 0) + ret = drm_intel_bo_mrb_exec(batch->bo, batch_end, + NULL, 0, 0, 0); + assert(ret == 0); +} + +/* Mostly copy+paste from gen6, except height, width, pitch moved */ +static uint32_t +gen7_bind_buf(struct intel_batchbuffer *batch, struct scratch_buf *buf, + uint32_t format, int is_dst) { + struct gen7_surface_state *ss; + uint32_t write_domain, read_domain; + int ret; + + if (is_dst) { + write_domain = read_domain = I915_GEM_DOMAIN_RENDER; + } else { + write_domain = 0; + read_domain = I915_GEM_DOMAIN_SAMPLER; + } + + ss = batch_alloc(batch, sizeof(*ss), 32); + ss->ss0.surface_type = GEN6_SURFACE_2D; + ss->ss0.surface_format = format; + ss->ss0.render_cache_read_write = 1; /* GEN7+ */ + ss->ss0.tiled_surface = buf->tiling != I915_TILING_NONE; + ss->ss0.tile_walk = buf->tiling == I915_TILING_Y; + + ss->ss1.base_addr = buf->bo->offset; + + ret = drm_intel_bo_emit_reloc(batch->bo, + batch_offset(batch, ss) + 4, + buf->bo, 0, + read_domain, write_domain); + assert(ret == 0); + + ss->ss2.height = buf_height(buf) - 1; + ss->ss2.width = buf_width(buf) - 1; + ss->ss3.pitch = buf->stride - 1; + + if (IS_HASWELL(batch->devid)) { + ss->ss7.shader_chanel_select_a = 4; + ss->ss7.shader_chanel_select_g = 5; + ss->ss7.shader_chanel_select_b = 6; + ss->ss7.shader_chanel_select_a = 7; + } + + return batch_offset(batch, ss); +} + +static uint32_t +gen7_bind_surfaces(struct intel_batchbuffer *batch, + struct scratch_buf *src, + struct scratch_buf *dst) { + uint32_t *binding_table; + + binding_table = batch_alloc(batch, 8, 32); + + binding_table[0] = + gen7_bind_buf(batch, dst, GEN6_SURFACEFORMAT_B8G8R8A8_UNORM, 1); + binding_table[1] = + gen7_bind_buf(batch, src, GEN6_SURFACEFORMAT_B8G8R8A8_UNORM, 0); + + return batch_offset(batch, binding_table); +} + +/* Mostly copy+paste from gen6, except wrap modes moved */ +static uint32_t +gen7_create_sampler(struct intel_batchbuffer *batch) { + struct gen7_sampler_state *ss; + + ss = batch_alloc(batch, sizeof(*ss), 32); + + ss->ss0.min_filter = GEN6_MAPFILTER_NEAREST; + ss->ss0.mag_filter = GEN6_MAPFILTER_NEAREST; + ss->ss3.r_wrap_mode = GEN6_TEXCOORDMODE_CLAMP; + ss->ss3.s_wrap_mode = GEN6_TEXCOORDMODE_CLAMP; + ss->ss3.t_wrap_mode = GEN6_TEXCOORDMODE_CLAMP; + + /* I've experimented with non-normalized coordinates and using the LD + * sampler fetch, but couldn't make it work. */ + ss->ss3.non_normalized_coord = 0; + + return batch_offset(batch, ss); +} + +/** + * gen7_fill_vertex_buffer_data populate vertex buffer with data. + * + * The vertex buffer consists of 3 vertices to construct a RECTLIST. The 4th + * vertex is implied (automatically derived by the HW). Each element has the + * destination offset, and the normalized texture offset (src). The rectangle + * itself will span the entire subsurface to be copied. + * + * see gen6_emit_vertex_elements + */ +static uint32_t +gen7_fill_vertex_buffer_data(struct intel_batchbuffer *batch, + struct scratch_buf *src, + uint32_t src_x, uint32_t src_y, + uint32_t dst_x, uint32_t dst_y, + uint32_t width, uint32_t height) { + void *ret; + + ret = batch->ptr; + + emit_vertex_2s(batch, dst_x + width, dst_y + height); + emit_vertex_normalized(batch, src_x + width, buf_width(src)); + emit_vertex_normalized(batch, src_y + height, buf_height(src)); + + emit_vertex_2s(batch, dst_x, dst_y + height); + emit_vertex_normalized(batch, src_x, buf_width(src)); + emit_vertex_normalized(batch, src_y + height, buf_height(src)); + + emit_vertex_2s(batch, dst_x, dst_y); + emit_vertex_normalized(batch, src_x, buf_width(src)); + emit_vertex_normalized(batch, src_y, buf_height(src)); + + return batch_offset(batch, ret); +} + +/** + * gen6_emit_vertex_elements - The vertex elements describe the contents of the + * vertex buffer. We pack the vertex buffer in a semi weird way, conforming to + * what gen6_rendercopy did. The most straightforward would be to store + * everything as floats. + * + * see gen7_fill_vertex_buffer_data() for where the corresponding elements are + * packed. + */ +static void +gen6_emit_vertex_elements(struct intel_batchbuffer *batch) { + /* + * The VUE layout + * dword 0-3: pad (0, 0, 0. 0) + * dword 4-7: position (x, y, 0, 1.0), + * dword 8-11: texture coordinate 0 (u0, v0, 0, 1.0) + */ + OUT_BATCH(GEN6_3DSTATE_VERTEX_ELEMENTS | (3 * 2 + 1 - 2)); + + /* Element state 0. These are 4 dwords of 0 required for the VUE format. + * We don't really know or care what they do. + */ + OUT_BATCH(0 << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID | + GEN6_SURFACEFORMAT_R32G32B32A32_FLOAT << VE0_FORMAT_SHIFT | + 0 << VE0_OFFSET_SHIFT); /* we specify 0, but it's really does not exist */ + OUT_BATCH(GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_0_SHIFT | + GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_1_SHIFT | + GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT | + GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_3_SHIFT); + + /* Element state 1 - Our "destination" vertices. These are passed down + * through the pipeline, and eventually make it to the pixel shader as + * the offsets in the destination surface. It's packed as the 16 + * signed/scaled because of gen6 rendercopy. I see no particular reason + * for doing this though. + */ + OUT_BATCH(0 << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID | + GEN6_SURFACEFORMAT_R16G16_SSCALED << VE0_FORMAT_SHIFT | + 0 << VE0_OFFSET_SHIFT); /* offsets vb in bytes */ + OUT_BATCH(GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT | + GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT | + GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT | + GEN6_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT); + + /* Element state 2. Last but not least we store the U,V components as + * normalized floats. These will be used in the pixel shader to sample + * from the source buffer. + */ + OUT_BATCH(0 << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID | + GEN6_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT | + 4 << VE0_OFFSET_SHIFT); /* offset vb in bytes */ + OUT_BATCH(GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT | + GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT | + GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT | + GEN6_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT); +} + +/** + * gen7_emit_vertex_buffer emit the vertex buffers command + * + * @batch + * @offset - bytw offset within the @batch where the vertex buffer starts. + */ +static void gen7_emit_vertex_buffer(struct intel_batchbuffer *batch, + uint32_t offset) { + OUT_BATCH(GEN6_3DSTATE_VERTEX_BUFFERS | (4 * 1 - 1)); + OUT_BATCH(0 << VB0_BUFFER_INDEX_SHIFT | /* VB 0th index */ + VB0_VERTEXDATA | + GEN7_VB0_BUFFER_ADDR_MOD_EN | /* Address Modify Enable */ + VERTEX_SIZE << VB0_BUFFER_PITCH_SHIFT); + OUT_RELOC(batch->bo, I915_GEM_DOMAIN_VERTEX, 0, offset); + OUT_RELOC(batch->bo, I915_GEM_DOMAIN_VERTEX, 0, offset + (VERTEX_SIZE * 3) - 1); + OUT_BATCH(0); +} + +static uint32_t +gen6_create_cc_state(struct intel_batchbuffer *batch) +{ + struct gen6_color_calc_state *cc_state; + cc_state = batch_alloc(batch, sizeof(*cc_state), 64); + return batch_offset(batch, cc_state); +} + +static uint32_t +gen6_create_depth_stencil_state(struct intel_batchbuffer *batch) +{ + struct gen6_depth_stencil_state *depth; + depth = batch_alloc(batch, sizeof(*depth), 64); + depth->ds0.stencil_enable = 0; + return batch_offset(batch, depth); +} + +static uint32_t +gen6_create_blend_state(struct intel_batchbuffer *batch) +{ + struct gen6_blend_state *blend; + blend = batch_alloc(batch, sizeof(*blend), 64); + blend->blend0.blend_enable = 0; + blend->blend1.pre_blend_clamp_enable = 1; + return batch_offset(batch, blend); +} + +static uint32_t +gen6_create_cc_viewport(struct intel_batchbuffer *batch) +{ + struct gen6_cc_viewport *vp; + + vp = batch_alloc(batch, sizeof(*vp), 32); + /* XXX I don't understand this */ + vp->min_depth = -1.e35; + vp->max_depth = 1.e35; + return batch_offset(batch, vp); +} + +static uint32_t +gen7_create_sf_clip_viewport(struct intel_batchbuffer *batch) { + /* XXX these are likely not needed */ + struct gen7_sf_clip_viewport *scv_state; + scv_state = batch_alloc(batch, sizeof(*scv_state), 64); + scv_state->guardband.xmin = 0; + scv_state->guardband.xmax = 1.0f; + scv_state->guardband.ymin = 0; + scv_state->guardband.ymax = 1.0f; + return batch_offset(batch, scv_state); +} + +static uint32_t +gen6_create_scissor_rect(struct intel_batchbuffer *batch) +{ + struct gen6_scissor_rect *scissor; + scissor = batch_alloc(batch, sizeof(*scissor), 64); + return batch_offset(batch, scissor); +} + + + + + +static void +gen6_emit_sip(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN6_STATE_SIP | 0); + OUT_BATCH(0); +} + +static void +gen7_emit_push_constants(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN7_3DSTATE_PUSH_CONSTANT_ALLOC_VS); + OUT_BATCH(0); + OUT_BATCH(GEN7_3DSTATE_PUSH_CONSTANT_ALLOC_HS); + OUT_BATCH(0); + OUT_BATCH(GEN7_3DSTATE_PUSH_CONSTANT_ALLOC_DS); + OUT_BATCH(0); + OUT_BATCH(GEN7_3DSTATE_PUSH_CONSTANT_ALLOC_GS); + OUT_BATCH(0); + OUT_BATCH(GEN7_3DSTATE_PUSH_CONSTANT_ALLOC_PS); + OUT_BATCH(0); +} + +static void +gen7_emit_state_base_address(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN6_STATE_BASE_ADDRESS | (10 - 2)); + /* general (stateless) */ + /* surface */ + /* instruction */ + /* indirect */ + /* dynamic */ + OUT_BATCH(0 | BASE_ADDRESS_MODIFY); + OUT_RELOC(batch->bo, I915_GEM_DOMAIN_SAMPLER, 0, BASE_ADDRESS_MODIFY); + OUT_RELOC(batch->bo, I915_GEM_DOMAIN_RENDER | I915_GEM_DOMAIN_INSTRUCTION, + 0, BASE_ADDRESS_MODIFY); + OUT_BATCH(0 | BASE_ADDRESS_MODIFY); + OUT_RELOC(batch->bo, I915_GEM_DOMAIN_INSTRUCTION, 0, BASE_ADDRESS_MODIFY); + + OUT_BATCH(0 | BASE_ADDRESS_MODIFY); + OUT_BATCH(0xfffff000 | BASE_ADDRESS_MODIFY); // copied from mesa + OUT_BATCH(0 | BASE_ADDRESS_MODIFY); + OUT_BATCH(0 | BASE_ADDRESS_MODIFY); +} + +static void +gen7_emit_urb(struct intel_batchbuffer *batch) { + /* XXX: Min valid values from mesa */ + const int vs_entries = 32; + const int vs_size = 2; + const int vs_start = 2; + + OUT_BATCH(GEN7_3DSTATE_URB_VS); + OUT_BATCH(vs_entries | ((vs_size - 1) << 16) | (vs_start << 25)); + OUT_BATCH(GEN7_3DSTATE_URB_GS); + OUT_BATCH(vs_start << 25); + OUT_BATCH(GEN7_3DSTATE_URB_HS); + OUT_BATCH(vs_start << 25); + OUT_BATCH(GEN7_3DSTATE_URB_DS); + OUT_BATCH(vs_start << 25); +} + +static void +gen7_emit_cc(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN7_3DSTATE_BLEND_STATE_POINTERS); + OUT_BATCH(cc.blend_state | 1); + + OUT_BATCH(GEN6_3DSTATE_CC_STATE_POINTERS); + OUT_BATCH(cc.cc_state | 1); + + OUT_BATCH(GEN7_3DSTATE_DS_STATE_POINTERS); + OUT_BATCH(cc.ds_state | 1); +} + +static void +gen7_emit_multisample(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN6_3DSTATE_MULTISAMPLE | 2); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN6_3DSTATE_SAMPLE_MASK); + OUT_BATCH(1); +} + +static void +gen7_emit_vs(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN7_3DSTATE_BINDING_TABLE_POINTERS_VS); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_SAMPLER_STATE_POINTERS_VS); + OUT_BATCH(0); + + OUT_BATCH(GEN6_3DSTATE_CONSTANT_VS | (7-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN6_3DSTATE_VS | (6-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); +} + +static void +gen7_emit_hs(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN7_3DSTATE_CONSTANT_HS | (7-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_HS | (7-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_BINDING_TABLE_POINTERS_HS); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_SAMPLER_STATE_POINTERS_HS); + OUT_BATCH(0); +} + +static void +gen7_emit_gs(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN7_3DSTATE_CONSTANT_GS | (7-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_GS | (7-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_BINDING_TABLE_POINTERS_GS); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_SAMPLER_STATE_POINTERS_GS); + OUT_BATCH(0); +} + +static void +gen7_emit_ds(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN7_3DSTATE_CONSTANT_DS | (7-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_DS | (6-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_BINDING_TABLE_POINTERS_DS); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_SAMPLER_STATE_POINTERS_DS); + OUT_BATCH(0); +} + +static void +gen7_emit_null_state(struct intel_batchbuffer *batch) { + gen7_emit_hs(batch); + OUT_BATCH(GEN7_3DSTATE_TE | (4-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + gen7_emit_gs(batch); + gen7_emit_ds(batch); + gen7_emit_vs(batch); +} + +static void +gen7_emit_clip(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN6_3DSTATE_CLIP | (4 - 2)); + OUT_BATCH(0); + OUT_BATCH(0); /* pass-through */ + OUT_BATCH(0); +} + +static void +gen7_emit_sf(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN7_3DSTATE_SBE | (14 - 2)); +#ifdef GPU_HANG + OUT_BATCH(0 << 22 | 1 << 11 | 1 << 4); +#else + OUT_BATCH(1 << 22 | 1 << 11 | 1 << 4); +#endif + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN6_3DSTATE_SF | (7 - 2)); + OUT_BATCH(0); + OUT_BATCH(GEN6_3DSTATE_SF_CULL_NONE); +// OUT_BATCH(2 << GEN6_3DSTATE_SF_TRIFAN_PROVOKE_SHIFT); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); +} + +static void +gen7_emit_ps(struct intel_batchbuffer *batch, uint32_t kernel) { + const int max_threads = 86; + + OUT_BATCH(GEN6_3DSTATE_WM | (3 - 2)); + OUT_BATCH(GEN7_WM_DISPATCH_ENABLE | + /* XXX: I don't understand the BARYCENTRIC stuff, but it + * appears we need it to put our setup data in the place we + * expect (g6, see below) */ + GEN7_3DSTATE_PS_PERSPECTIVE_PIXEL_BARYCENTRIC); + OUT_BATCH(0); + + OUT_BATCH(GEN6_3DSTATE_CONSTANT_PS | (7-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_PS | (8-2)); + OUT_BATCH(kernel); + OUT_BATCH(1 << GEN6_3DSTATE_WM_SAMPLER_COUNT_SHITF | + 2 << GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT); + OUT_BATCH(0); /* scratch space stuff */ + if (IS_HASWELL(batch->devid)) { + OUT_BATCH((max_threads - 1) << GEN7_3DSTATE_WM_MAX_THREADS_SHIFT | + GEN7_3DSTATE_PS_ATTRIBUTE_ENABLED | + GEN6_3DSTATE_WM_16_DISPATCH_ENABLE); + } else { + OUT_BATCH((max_threads - 1) << HSW_3DSTATE_WM_MAX_THREADS_SHIFT | + GEN7_3DSTATE_PS_ATTRIBUTE_ENABLED | + GEN6_3DSTATE_WM_16_DISPATCH_ENABLE); + } + OUT_BATCH(6 << GEN6_3DSTATE_WM_DISPATCH_START_GRF_0_SHIFT); + OUT_BATCH(0); // kernel 1 + OUT_BATCH(0); // kernel 2 +} + +static void +gen7_emit_depth(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN7_3DSTATE_DEPTH_BUFFER | (7-2)); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_HIER_DEPTH_BUFFER | (3-2)); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(GEN7_3DSTATE_STENCIL_BUFFER | (3-2)); + OUT_BATCH(0); + OUT_BATCH(0); +} + +static void +gen7_emit_clear(struct intel_batchbuffer *batch) { + OUT_BATCH(GEN7_3DSTATE_CLEAR_PARAMS | (3-2)); + OUT_BATCH(0); + OUT_BATCH(1); // clear valid +} + +static void +gen6_emit_drawing_rectangle(struct intel_batchbuffer *batch, struct scratch_buf *dst) +{ + OUT_BATCH(GEN6_3DSTATE_DRAWING_RECTANGLE | (4 - 2)); + OUT_BATCH(0); + OUT_BATCH((buf_height(dst) - 1) << 16 | (buf_width(dst) - 1)); + OUT_BATCH(0); +} + +/* Vertex elements MUST be defined before this according to spec */ +static void gen7_emit_primitive(struct intel_batchbuffer *batch, uint32_t offset) +{ + OUT_BATCH(GEN6_3DPRIMITIVE | (7-2)); + OUT_BATCH(_3DPRIM_RECTLIST); + OUT_BATCH(3); /* vertex count */ + OUT_BATCH(0); /* We're specifying this instead with offset in GEN6_3DSTATE_VERTEX_BUFFERS */ + OUT_BATCH(1); /* single instance */ + OUT_BATCH(0); /* start instance location */ + OUT_BATCH(0); /* index buffer offset, ignored */ +} + +/* The general rule is if it's named gen6 it is directly copied from + * gen6_render_copyfunc. + * + * This sets up most of the 3d pipeline, and most of that to NULL state. The + * docs aren't specific about exactly what must be set up NULL, but the general + * rule is we could be run at any time, and so the most state we set to NULL, + * the better our odds of success. + * + * +---------------+ <---- 4096 + * | ^ | + * | | | + * | various | + * | state | + * | | | + * |_______|_______| <---- 2048 + ? + * | ^ | + * | | | + * | batch | + * | commands | + * | | | + * | | | + * +---------------+ <---- 0 + ? + * + * The batch commands point to state within tthe batch, so all state offsets should be + * 0 < offset < 4096. Both commands and state build upwards, and are constructed + * in that order. This means too many batch commands can delete state if not + * careful. + * + */ + +#define BATCH_STATE_SPLIT 2048 +void gen7_render_copyfunc(struct intel_batchbuffer *batch, + struct scratch_buf *src, unsigned src_x, unsigned src_y, + unsigned width, unsigned height, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y) +{ + uint32_t ps_sampler_state, ps_kernel_off, ps_binding_table; + uint32_t scissor_state; + uint32_t vertex_buffer; + uint32_t batch_end; + + intel_batchbuffer_flush(batch); + + batch_align(batch, 8); + + batch->ptr = &batch->buffer[BATCH_STATE_SPLIT]; + + ps_binding_table = gen7_bind_surfaces(batch, src, dst); + ps_sampler_state = gen7_create_sampler(batch); + ps_kernel_off = batch_copy(batch, ps_kernel, sizeof(ps_kernel), 64); + vertex_buffer = gen7_fill_vertex_buffer_data(batch, src, src_x, src_y, dst_x, dst_y, width, height); + cc.cc_state = gen6_create_cc_state(batch); + cc.ds_state = gen6_create_depth_stencil_state(batch); + cc.blend_state = gen6_create_blend_state(batch); + viewport.cc_state = gen6_create_cc_viewport(batch); + viewport.sf_clip_state = gen7_create_sf_clip_viewport(batch); + scissor_state = gen6_create_scissor_rect(batch); + /* TODO: theree is other state which isn't setup */ + + assert(batch->ptr < &batch->buffer[4095]); + + batch->ptr = batch->buffer; + + /* Start emitting the commands. The order roughly follows the mesa blorp + * order */ + OUT_BATCH(GEN6_PIPELINE_SELECT | PIPELINE_SELECT_3D); + + gen6_emit_sip(batch); + + gen7_emit_push_constants(batch); + + gen7_emit_state_base_address(batch); + + OUT_BATCH(GEN7_3DSTATE_VIEWPORT_STATE_POINTERS_CC); + OUT_BATCH(viewport.cc_state); + OUT_BATCH(GEN7_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP); + OUT_BATCH(viewport.sf_clip_state); + + gen7_emit_urb(batch); + + gen7_emit_cc(batch); + + gen7_emit_multisample(batch); + + gen7_emit_null_state(batch); + + OUT_BATCH(GEN7_3DSTATE_STREAMOUT | 1); + OUT_BATCH(0); + OUT_BATCH(0); + + gen7_emit_clip(batch); + + gen7_emit_sf(batch); + + OUT_BATCH(GEN7_3DSTATE_BINDING_TABLE_POINTERS_PS); + OUT_BATCH(ps_binding_table); + + OUT_BATCH(GEN7_3DSTATE_SAMPLER_STATE_POINTERS_PS); + OUT_BATCH(ps_sampler_state); + + gen7_emit_ps(batch, ps_kernel_off); + + OUT_BATCH(GEN6_3DSTATE_SCISSOR_STATE_POINTERS); + OUT_BATCH(scissor_state); + + gen7_emit_depth(batch); + + gen7_emit_clear(batch); + + gen6_emit_drawing_rectangle(batch, dst); + + gen7_emit_vertex_buffer(batch, vertex_buffer); + gen6_emit_vertex_elements(batch); + + gen7_emit_primitive(batch, vertex_buffer); + + OUT_BATCH(MI_BATCH_BUFFER_END); + + batch_end = batch_align(batch, 8); + assert(batch_end < BATCH_STATE_SPLIT); + + dump_batch(batch); + + gen6_render_flush(batch, batch_end); + intel_batchbuffer_reset(batch); +} + +#if DEBUG_RENDERCPY +static void dump_batch(struct intel_batchbuffer *batch) { + int fd = open("/tmp/i965-batchbuffers.dump", O_WRONLY | O_CREAT, 0666); + if (fd != -1) { + write(fd, batch->buffer, 4096); + fd = close(fd); + } +} +#endif diff --git a/lib/rendercopy_i830.c b/lib/rendercopy_i830.c new file mode 100644 index 00000000..28c3e99e --- /dev/null +++ b/lib/rendercopy_i830.c @@ -0,0 +1,229 @@ +#include "i830_reg.h" +#include "rendercopy.h" + +#define TB0C_LAST_STAGE (1 << 31) +#define TB0C_RESULT_SCALE_1X (0 << 29) +#define TB0C_RESULT_SCALE_2X (1 << 29) +#define TB0C_RESULT_SCALE_4X (2 << 29) +#define TB0C_OP_ARG1 (1 << 25) +#define TB0C_OP_MODULE (3 << 25) +#define TB0C_OUTPUT_WRITE_CURRENT (0 << 24) +#define TB0C_OUTPUT_WRITE_ACCUM (1 << 24) +#define TB0C_ARG3_REPLICATE_ALPHA (1<<23) +#define TB0C_ARG3_INVERT (1<<22) +#define TB0C_ARG3_SEL_XXX +#define TB0C_ARG2_REPLICATE_ALPHA (1<<17) +#define TB0C_ARG2_INVERT (1<<16) +#define TB0C_ARG2_SEL_ONE (0 << 12) +#define TB0C_ARG2_SEL_FACTOR (1 << 12) +#define TB0C_ARG2_SEL_TEXEL0 (6 << 12) +#define TB0C_ARG2_SEL_TEXEL1 (7 << 12) +#define TB0C_ARG2_SEL_TEXEL2 (8 << 12) +#define TB0C_ARG2_SEL_TEXEL3 (9 << 12) +#define TB0C_ARG1_REPLICATE_ALPHA (1<<11) +#define TB0C_ARG1_INVERT (1<<10) +#define TB0C_ARG1_SEL_ONE (0 << 6) +#define TB0C_ARG1_SEL_TEXEL0 (6 << 6) +#define TB0C_ARG1_SEL_TEXEL1 (7 << 6) +#define TB0C_ARG1_SEL_TEXEL2 (8 << 6) +#define TB0C_ARG1_SEL_TEXEL3 (9 << 6) +#define TB0C_ARG0_REPLICATE_ALPHA (1<<5) +#define TB0C_ARG0_SEL_XXX + +#define TB0A_CTR_STAGE_ENABLE (1<<31) +#define TB0A_RESULT_SCALE_1X (0 << 29) +#define TB0A_RESULT_SCALE_2X (1 << 29) +#define TB0A_RESULT_SCALE_4X (2 << 29) +#define TB0A_OP_ARG1 (1 << 25) +#define TB0A_OP_MODULE (3 << 25) +#define TB0A_OUTPUT_WRITE_CURRENT (0<<24) +#define TB0A_OUTPUT_WRITE_ACCUM (1<<24) +#define TB0A_CTR_STAGE_SEL_BITS_XXX +#define TB0A_ARG3_SEL_XXX +#define TB0A_ARG3_INVERT (1<<17) +#define TB0A_ARG2_INVERT (1<<16) +#define TB0A_ARG2_SEL_ONE (0 << 12) +#define TB0A_ARG2_SEL_TEXEL0 (6 << 12) +#define TB0A_ARG2_SEL_TEXEL1 (7 << 12) +#define TB0A_ARG2_SEL_TEXEL2 (8 << 12) +#define TB0A_ARG2_SEL_TEXEL3 (9 << 12) +#define TB0A_ARG1_INVERT (1<<10) +#define TB0A_ARG1_SEL_ONE (0 << 6) +#define TB0A_ARG1_SEL_TEXEL0 (6 << 6) +#define TB0A_ARG1_SEL_TEXEL1 (7 << 6) +#define TB0A_ARG1_SEL_TEXEL2 (8 << 6) +#define TB0A_ARG1_SEL_TEXEL3 (9 << 6) + + +static void gen2_emit_invariant(struct intel_batchbuffer *batch) +{ + int i; + + for (i = 0; i < 4; i++) { + OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(i)); + OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD | MAP_UNIT(i) | + DISABLE_TEX_STREAM_BUMP | + ENABLE_TEX_STREAM_COORD_SET | TEX_STREAM_COORD_SET(i) | + ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(i)); + OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM); + OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(i)); + } + + OUT_BATCH(_3DSTATE_MAP_COORD_SETBIND_CMD); + OUT_BATCH(TEXBIND_SET3(TEXCOORDSRC_VTXSET_3) | + TEXBIND_SET2(TEXCOORDSRC_VTXSET_2) | + TEXBIND_SET1(TEXCOORDSRC_VTXSET_1) | + TEXBIND_SET0(TEXCOORDSRC_VTXSET_0)); + + OUT_BATCH(_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT); + + OUT_BATCH(_3DSTATE_VERTEX_TRANSFORM); + OUT_BATCH(DISABLE_VIEWPORT_TRANSFORM | DISABLE_PERSPECTIVE_DIVIDE); + + OUT_BATCH(_3DSTATE_W_STATE_CMD); + OUT_BATCH(MAGIC_W_STATE_DWORD1); + OUT_BATCH(0x3f800000 /* 1.0 in IEEE float */ ); + + OUT_BATCH(_3DSTATE_INDPT_ALPHA_BLEND_CMD | + DISABLE_INDPT_ALPHA_BLEND | + ENABLE_ALPHA_BLENDFUNC | ABLENDFUNC_ADD); + + OUT_BATCH(_3DSTATE_CONST_BLEND_COLOR_CMD); + OUT_BATCH(0); + + OUT_BATCH(_3DSTATE_MODES_1_CMD | + ENABLE_COLR_BLND_FUNC | BLENDFUNC_ADD | + ENABLE_SRC_BLND_FACTOR | SRC_BLND_FACT(BLENDFACTOR_ONE) | + ENABLE_DST_BLND_FACTOR | DST_BLND_FACT(BLENDFACTOR_ZERO)); + + OUT_BATCH(_3DSTATE_ENABLES_1_CMD | + DISABLE_LOGIC_OP | + DISABLE_STENCIL_TEST | + DISABLE_DEPTH_BIAS | + DISABLE_SPEC_ADD | + DISABLE_FOG | + DISABLE_ALPHA_TEST | + DISABLE_DEPTH_TEST | + ENABLE_COLOR_BLEND); + + OUT_BATCH(_3DSTATE_ENABLES_2_CMD | + DISABLE_STENCIL_WRITE | + DISABLE_DITHER | + DISABLE_DEPTH_WRITE | + ENABLE_COLOR_MASK | + ENABLE_COLOR_WRITE | + ENABLE_TEX_CACHE); +} + +static void gen2_emit_target(struct intel_batchbuffer *batch, + struct scratch_buf *dst) +{ + uint32_t tiling; + + tiling = 0; + if (dst->tiling != I915_TILING_NONE) + tiling = BUF_3D_TILED_SURFACE; + if (dst->tiling == I915_TILING_Y) + tiling |= BUF_3D_TILE_WALK_Y; + + OUT_BATCH(_3DSTATE_BUF_INFO_CMD); + OUT_BATCH(BUF_3D_ID_COLOR_BACK | tiling | BUF_3D_PITCH(dst->stride)); + OUT_RELOC(dst->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + + OUT_BATCH(_3DSTATE_DST_BUF_VARS_CMD); + OUT_BATCH(COLR_BUF_ARGB8888 | + DSTORG_HORT_BIAS(0x8) | + DSTORG_VERT_BIAS(0x8)); + + OUT_BATCH(_3DSTATE_DRAW_RECT_CMD); + OUT_BATCH(0); + OUT_BATCH(0); /* ymin, xmin */ + OUT_BATCH(DRAW_YMAX(buf_height(dst) - 1) | + DRAW_XMAX(buf_width(dst) - 1)); + OUT_BATCH(0); /* yorig, xorig */ +} + +static void gen2_emit_texture(struct intel_batchbuffer *batch, + struct scratch_buf *src, + int unit) +{ + uint32_t tiling; + + tiling = 0; + if (src->tiling != I915_TILING_NONE) + tiling = TM0S1_TILED_SURFACE; + if (src->tiling == I915_TILING_Y) + tiling |= TM0S1_TILE_WALK; + + OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | LOAD_TEXTURE_MAP(unit) | 4); + OUT_RELOC(src->bo, I915_GEM_DOMAIN_SAMPLER, 0, 0); + OUT_BATCH((buf_height(src) - 1) << TM0S1_HEIGHT_SHIFT | + (buf_width(src) - 1) << TM0S1_WIDTH_SHIFT | + MAPSURF_32BIT | MT_32BIT_ARGB8888 | tiling); + OUT_BATCH((src->stride / 4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D); + OUT_BATCH(FILTER_NEAREST << TM0S3_MAG_FILTER_SHIFT | + FILTER_NEAREST << TM0S3_MIN_FILTER_SHIFT | + MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT); + OUT_BATCH(0); /* default color */ + + OUT_BATCH(_3DSTATE_MAP_COORD_SET_CMD | TEXCOORD_SET(unit) | + ENABLE_TEXCOORD_PARAMS | TEXCOORDS_ARE_NORMAL | + TEXCOORDTYPE_CARTESIAN | + ENABLE_ADDR_V_CNTL | TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP_BORDER) | + ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP_BORDER)); +} + +static void gen2_emit_copy_pipeline(struct intel_batchbuffer *batch) +{ + OUT_BATCH(_3DSTATE_INDPT_ALPHA_BLEND_CMD | DISABLE_INDPT_ALPHA_BLEND); + OUT_BATCH(_3DSTATE_ENABLES_1_CMD | DISABLE_LOGIC_OP | + DISABLE_STENCIL_TEST | DISABLE_DEPTH_BIAS | + DISABLE_SPEC_ADD | DISABLE_FOG | DISABLE_ALPHA_TEST | + DISABLE_COLOR_BLEND | DISABLE_DEPTH_TEST); + + OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | + LOAD_TEXTURE_BLEND_STAGE(0) | 1); + OUT_BATCH(TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | + TB0C_OUTPUT_WRITE_CURRENT | + TB0C_OP_ARG1 | TB0C_ARG1_SEL_TEXEL0); + OUT_BATCH(TB0A_RESULT_SCALE_1X | TB0A_OUTPUT_WRITE_CURRENT | + TB0A_OP_ARG1 | TB0A_ARG1_SEL_TEXEL0); +} + +void gen2_render_copyfunc(struct intel_batchbuffer *batch, + struct scratch_buf *src, unsigned src_x, unsigned src_y, + unsigned width, unsigned height, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y) +{ + gen2_emit_invariant(batch); + gen2_emit_copy_pipeline(batch); + + gen2_emit_target(batch, dst); + gen2_emit_texture(batch, src, 0); + + OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | + I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2); + OUT_BATCH(1<<12); + OUT_BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY); + OUT_BATCH(S8_ENABLE_COLOR_BUFFER_WRITE); + + OUT_BATCH(_3DSTATE_VERTEX_FORMAT_2_CMD | TEXCOORDFMT_2D << 0); + + OUT_BATCH(PRIM3D_INLINE | PRIM3D_RECTLIST | (3*4 -1)); + emit_vertex(batch, dst_x + width); + emit_vertex(batch, dst_y + height); + emit_vertex_normalized(batch, src_x + width, buf_width(src)); + emit_vertex_normalized(batch, src_y + height, buf_height(src)); + + emit_vertex(batch, dst_x); + emit_vertex(batch, dst_y + height); + emit_vertex_normalized(batch, src_x, buf_width(src)); + emit_vertex_normalized(batch, src_y + height, buf_height(src)); + + emit_vertex(batch, dst_x); + emit_vertex(batch, dst_y); + emit_vertex_normalized(batch, src_x, buf_width(src)); + emit_vertex_normalized(batch, src_y, buf_height(src)); + + intel_batchbuffer_flush(batch); +} diff --git a/lib/rendercopy_i915.c b/lib/rendercopy_i915.c new file mode 100644 index 00000000..4b15dfe3 --- /dev/null +++ b/lib/rendercopy_i915.c @@ -0,0 +1,180 @@ +#include "i915_reg.h" +#include "i915_3d.h" +#include "rendercopy.h" + +void gen3_render_copyfunc(struct intel_batchbuffer *batch, + struct scratch_buf *src, unsigned src_x, unsigned src_y, + unsigned width, unsigned height, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y) +{ + /* invariant state */ + { + OUT_BATCH(_3DSTATE_AA_CMD | + AA_LINE_ECAAR_WIDTH_ENABLE | + AA_LINE_ECAAR_WIDTH_1_0 | + AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0); + OUT_BATCH(_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD | + IAB_MODIFY_ENABLE | + IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) | + IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE << + IAB_SRC_FACTOR_SHIFT) | + IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO << + IAB_DST_FACTOR_SHIFT)); + OUT_BATCH(_3DSTATE_DFLT_DIFFUSE_CMD); + OUT_BATCH(0); + OUT_BATCH(_3DSTATE_DFLT_SPEC_CMD); + OUT_BATCH(0); + OUT_BATCH(_3DSTATE_DFLT_Z_CMD); + OUT_BATCH(0); + OUT_BATCH(_3DSTATE_COORD_SET_BINDINGS | + CSB_TCB(0, 0) | + CSB_TCB(1, 1) | + CSB_TCB(2, 2) | + CSB_TCB(3, 3) | + CSB_TCB(4, 4) | + CSB_TCB(5, 5) | CSB_TCB(6, 6) | CSB_TCB(7, 7)); + OUT_BATCH(_3DSTATE_RASTER_RULES_CMD | + ENABLE_POINT_RASTER_RULE | + OGL_POINT_RASTER_RULE | + ENABLE_LINE_STRIP_PROVOKE_VRTX | + ENABLE_TRI_FAN_PROVOKE_VRTX | + LINE_STRIP_PROVOKE_VRTX(1) | + TRI_FAN_PROVOKE_VRTX(2) | ENABLE_TEXKILL_3D_4D | TEXKILL_4D); + OUT_BATCH(_3DSTATE_MODES_4_CMD | + ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) | + ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) | + ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff)); + OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2); + OUT_BATCH(0x00000000); /* Disable texture coordinate wrap-shortest */ + OUT_BATCH((1 << S4_POINT_WIDTH_SHIFT) | + S4_LINE_WIDTH_ONE | + S4_CULLMODE_NONE | + S4_VFMT_XY); + OUT_BATCH(0x00000000); /* Stencil. */ + OUT_BATCH(_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT); + OUT_BATCH(_3DSTATE_SCISSOR_RECT_0_CMD); + OUT_BATCH(0); + OUT_BATCH(0); + OUT_BATCH(_3DSTATE_DEPTH_SUBRECT_DISABLE); + OUT_BATCH(_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */ + OUT_BATCH(0); + OUT_BATCH(_3DSTATE_STIPPLE); + OUT_BATCH(0x00000000); + OUT_BATCH(_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0); + } + + /* samler state */ + { +#define TEX_COUNT 1 + uint32_t tiling_bits = 0; + if (src->tiling != I915_TILING_NONE) + tiling_bits = MS3_TILED_SURFACE; + if (src->tiling == I915_TILING_Y) + tiling_bits |= MS3_TILE_WALK; + + OUT_BATCH(_3DSTATE_MAP_STATE | (3 * TEX_COUNT)); + OUT_BATCH((1 << TEX_COUNT) - 1); + OUT_RELOC(src->bo, I915_GEM_DOMAIN_SAMPLER, 0, 0); + OUT_BATCH(MAPSURF_32BIT | MT_32BIT_ARGB8888 | + tiling_bits | + (buf_height(src) - 1) << MS3_HEIGHT_SHIFT | + (buf_width(src) - 1) << MS3_WIDTH_SHIFT); + OUT_BATCH((src->stride/4-1) << MS4_PITCH_SHIFT); + + OUT_BATCH(_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT)); + OUT_BATCH((1 << TEX_COUNT) - 1); + OUT_BATCH(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT | + FILTER_NEAREST << SS2_MAG_FILTER_SHIFT | + FILTER_NEAREST << SS2_MIN_FILTER_SHIFT); + OUT_BATCH(TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT | + TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT | + 0 << SS3_TEXTUREMAP_INDEX_SHIFT); + OUT_BATCH(0x00000000); + } + + /* render target state */ + { + uint32_t tiling_bits = 0; + if (dst->tiling != I915_TILING_NONE) + tiling_bits = BUF_3D_TILED_SURFACE; + if (dst->tiling == I915_TILING_Y) + tiling_bits |= BUF_3D_TILE_WALK_Y; + + OUT_BATCH(_3DSTATE_BUF_INFO_CMD); + OUT_BATCH(BUF_3D_ID_COLOR_BACK | tiling_bits | + BUF_3D_PITCH(dst->stride)); + OUT_RELOC(dst->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + + OUT_BATCH(_3DSTATE_DST_BUF_VARS_CMD); + OUT_BATCH(COLR_BUF_ARGB8888 | + DSTORG_HORT_BIAS(0x8) | + DSTORG_VERT_BIAS(0x8)); + + /* draw rect is unconditional */ + OUT_BATCH(_3DSTATE_DRAW_RECT_CMD); + OUT_BATCH(0x00000000); + OUT_BATCH(0x00000000); /* ymin, xmin */ + OUT_BATCH(DRAW_YMAX(buf_height(dst) - 1) | + DRAW_XMAX(buf_width(dst) - 1)); + /* yorig, xorig (relate to color buffer?) */ + OUT_BATCH(0x00000000); + } + + /* texfmt */ + { + OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | + I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2); + OUT_BATCH((4 << S1_VERTEX_WIDTH_SHIFT) | + (4 << S1_VERTEX_PITCH_SHIFT)); + OUT_BATCH(~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) | S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D)); + OUT_BATCH(S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE | + BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT | + BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT | + BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT); + } + + /* frage shader */ + { + OUT_BATCH(_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2)); + /* decl FS_T0 */ + OUT_BATCH(D0_DCL | + REG_TYPE(FS_T0) << D0_TYPE_SHIFT | + REG_NR(FS_T0) << D0_NR_SHIFT | + ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + OUT_BATCH(0); + OUT_BATCH(0); + /* decl FS_S0 */ + OUT_BATCH(D0_DCL | + (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) | + (REG_NR(FS_S0) << D0_NR_SHIFT) | + ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + OUT_BATCH(0); + OUT_BATCH(0); + /* texld(FS_OC, FS_S0, FS_T0 */ + OUT_BATCH(T0_TEXLD | + (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) | + (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) | + (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT)); + OUT_BATCH((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) | + (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT)); + OUT_BATCH(0); + } + + OUT_BATCH(PRIM3D_RECTLIST | (3*4 - 1)); + emit_vertex(batch, dst_x + width); + emit_vertex(batch, dst_y + height); + emit_vertex(batch, src_x + width); + emit_vertex(batch, src_y + height); + + emit_vertex(batch, dst_x); + emit_vertex(batch, dst_y + height); + emit_vertex(batch, src_x); + emit_vertex(batch, src_y + height); + + emit_vertex(batch, dst_x); + emit_vertex(batch, dst_y); + emit_vertex(batch, src_x); + emit_vertex(batch, src_y); + + intel_batchbuffer_flush(batch); +} diff --git a/man/Makefile.am b/man/Makefile.am new file mode 100644 index 00000000..0d04f934 --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1,30 @@ +appmandir = $(APP_MAN_DIR) +appman_PRE = \ + intel_audio_dump.man \ + intel_bios_dumper.man \ + intel_bios_reader.man \ + intel_error_decode.man \ + intel_gpu_top.man \ + intel_gtt.man \ + intel_infoframes.man \ + intel_lid.man \ + intel_panel_fitter.man \ + intel_reg_dumper.man \ + intel_reg_read.man \ + intel_reg_write.man \ + intel_stepping.man \ + intel_upload_blit_large.man \ + intel_upload_blit_large_gtt.man \ + intel_upload_blit_large_map.man \ + intel_upload_blit_small.man + +appman_DATA = $(appman_PRE:man=$(APP_MAN_SUFFIX)) + +EXTRA_DIST = $(appman_PRE) +CLEANFILES = $(appman_DATA) + +# String replacements in MAN_SUBSTS now come from xorg-macros.m4 via configure +SUFFIXES = .$(APP_MAN_SUFFIX) .man + +.man.$(APP_MAN_SUFFIX): + $(AM_V_GEN)$(SED) $(MAN_SUBSTS) < $< > $@ diff --git a/man/intel_audio_dump.man b/man/intel_audio_dump.man new file mode 100644 index 00000000..89a81ec4 --- /dev/null +++ b/man/intel_audio_dump.man @@ -0,0 +1,11 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_audio_dump __appmansuffix__ __xorgversion__ +.SH NAME +intel_audio_dump \- Dumps the Intel GPU registers for HDMI audio setup. +.SH SYNOPSIS +.B intel_audio_dump +.SH DESCRIPTION +.B intel_audio_dump +dumps and decodes registers containing the configuration of HDMI audio +handling on Intel GPUs. diff --git a/man/intel_bios_dumper.man b/man/intel_bios_dumper.man new file mode 100644 index 00000000..c9acaa46 --- /dev/null +++ b/man/intel_bios_dumper.man @@ -0,0 +1,14 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_bios_dumper __appmansuffix__ __xorgversion__ +.SH NAME +intel_bios_dumper \- Saves the Intel video BIOS contents to a file. +.SH SYNOPSIS +.B intel_bios_dumper \fIfilename\fR +.SH DESCRIPTION +.B intel_bios_dumper +is a tool to save the contents of the Intel video BIOS to a file. It +can then be parsed offline for debugging issues with the video bios +table handling. +.SH SEE ALSO +.BR intel_bios_reader(1) diff --git a/man/intel_bios_reader.man b/man/intel_bios_reader.man new file mode 100644 index 00000000..2f125fc9 --- /dev/null +++ b/man/intel_bios_reader.man @@ -0,0 +1,15 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_bios_reader __appmansuffix__ __xorgversion__ +.SH NAME +intel_bios_reader \- Parses an Intel BIOS and displays many of its tables +.SH SYNOPSIS +.B intel_bios_reader \fIfilename\fR +.SH DESCRIPTION +.B intel_bios_reader +is a tool to parse the contents of an Intel video BIOS file. The file +can come from intel_bios_dumper. This can be used for quick debugging +of video bios table handling, which is harder when done inside of the +kernel graphics driver. +.SH SEE ALSO +.BR intel_bios_dumper (1) diff --git a/man/intel_error_decode.man b/man/intel_error_decode.man new file mode 100644 index 00000000..e53d898d --- /dev/null +++ b/man/intel_error_decode.man @@ -0,0 +1,20 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_error_decode __appmansuffix__ __xorgversion__ +.SH NAME +intel_error_decode \- Decodes an Intel GPU dump automatically captured by the kernel at the time of an error. +.SH SYNOPSIS +.nf +.B intel_error_decode +.B intel_error_decode [ filename ] +.fi +.SH DESCRIPTION +.B intel_error_decode +is a tool that decodes the instructions and state of the GPU at the time of +an error. It requires kernel 2.6.34 or newer, and either debugfs mounted on +/sys/kernel/debug or /debug containing a current i915_error_state or you can +pass a file containing a saved error. +.SS Options +.TP +.B filename +Decodes a previously saved error. diff --git a/man/intel_gpu_top.man b/man/intel_gpu_top.man new file mode 100644 index 00000000..b307a238 --- /dev/null +++ b/man/intel_gpu_top.man @@ -0,0 +1,41 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_gpu_top __appmansuffix__ __xorgversion__ +.SH NAME +intel_gpu_top \- Display a top-like summary of Intel GPU usage +.SH SYNOPSIS +.nf +.B intel_gpu_top +.B intel_gpu_top [ parameters ] +.SH DESCRIPTION +.B intel_gpu_top +is a tool to display usage information of an Intel GPU. It requires root +privilege to map the graphics device. +.SS Options +.TP +.B -s [samples per second] +number of samples to acquire per second +.TP +.B -o [output file] +collect usage statistics to [file]. If file is "-", run non-interactively +and output statistics to stdout. +.TP +.B -e ["command to profile"] +execute a command, and leave when it is finished. Note that the entire command +with all parameters should be included as one parameter. +.TP +.B -h +show usage notes +.SH EXAMPLES +.TP +intel_gpu_top -o "cairo-trace-gvim.log" -s 100 -e "cairo-perf-trace /tmp/gvim" +will run cairo-perf-trace with /tmp/gvim trace, non-interactively, saving the +statistics into cairo-trace-gvim.log file, and collecting 100 samples per +second. +.PP +Note that idle units are not +displayed, so an entirely idle GPU will only display the ring status and +header. +.SH BUGS +Some GPUs report some units as busy when they aren't, such that even when +idle and not hung, it will show up as 100% busy. diff --git a/man/intel_gtt.man b/man/intel_gtt.man new file mode 100644 index 00000000..8b23f287 --- /dev/null +++ b/man/intel_gtt.man @@ -0,0 +1,14 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_gtt __appmansuffix__ __xorgversion__ +.SH NAME +intel_gtt \- Dump the contents of an Intel GPU's GTT +.SH SYNOPSIS +.B intel_gtt +.SH DESCRIPTION +.B intel_gtt +is a tool to view the contents of the GTT on an Intel GPU. The GTT is +the page table that maps between GPU addresses and system memory. +This tool can be useful in debugging the Linux AGP driver +initialization of the chip or in debugging later overwriting of the +GTT with garbage data. diff --git a/man/intel_infoframes.man b/man/intel_infoframes.man new file mode 100644 index 00000000..b0159492 --- /dev/null +++ b/man/intel_infoframes.man @@ -0,0 +1,26 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_infoframes __appmansuffix__ __xorgversion__ +.SH NAME +intel_infoframes \- View and change HDMI InfoFrames +.SH SYNOPSIS +.B intel_infoframes +.SH DESCRIPTION +.B intel_infoframes +is a tool to view and change the HDMI InfoFrames sent by the GPU. Its main +purpose is to be used as a debugging tool. In some cases (e.g., when +changing modes) the Kernel will undo the changes made by this tool. + +Descriptions of the InfoFrame fields can be found on the HDMI and CEA-861 +specifications. + +Use the +.B -h +or +.B --help +options to learn how to use the command +.SH LIMITATIONS +Not all HDMI monitors respect the InfoFrames sent to them. Only GEN 4 +or newer hardware is supported yet. +.SH SEE ALSO +HDMI specification, CEA-861 specification. diff --git a/man/intel_lid.man b/man/intel_lid.man new file mode 100644 index 00000000..d06af79b --- /dev/null +++ b/man/intel_lid.man @@ -0,0 +1,12 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_lid __appmansuffix__ __xorgversion__ +.SH NAME +intel_ \- Polls the values of different reports about laptop lid state. +.SH SYNOPSIS +.B intel_lid +.SH DESCRIPTION +.B intel_lid +is a tool to poll ACPI and the BIOS scratch register's reporting of +laptop lid state. This can be used for debugging issues with laptop +modesetting for lid opening and closing. diff --git a/man/intel_panel_fitter.man b/man/intel_panel_fitter.man new file mode 100644 index 00000000..9a46a2ed --- /dev/null +++ b/man/intel_panel_fitter.man @@ -0,0 +1,50 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_panel_fitter __appmansuffix__ __xorgversion__ +.SH NAME +intel_panel_fitter \- Change the panel fitter settings +.SH SYNOPSIS +.B intel_panel_fitter [options] +.SH DESCRIPTION +.B intel_panel_fitter +is a tool that allows you to change the panel fitter settings, so you can change +the size of the screen being displayed on your monitor without changing the real +pixel size of your desktop. The biggest use case for this tool is to work around +overscan done by TVs and some monitors in interlaced mode. +.SS Options +.TP +.B -p [pipe] +pipe to be used (A, B or C, but C is only present on Ivy Bridge and newer). +.TP +.B -x [value] +final screen width size in pixels (needs -p option). +.TP +.B -y [value] +final screen height size in pixels (needs -p option). +.TP +.B -d +disable panel fitter (needs -p option, ignores -x and -y options). +.TP +.B -l +list current state of each pipe. +.TP +.B -h +prints the help message. +.SS + +.SH EXAMPLES +.TP +.B intel_panel_fitter -l +will list the current status of each pipe, so you can decide what to do. +.TP +.B intel_panel_fitter -p A -x 1850 -y 1040 +will change the pipe A size to 1850x1040 pixels. +.TP +.B intel_panel_fitter -p A -d +will disable the panel fitter for pipe A. + +.SH NOTES +In the future, there will be support for this feature inside the Linux Kernel. + +Machines older than Ironlake are still not supported, but support may be +possible to implement. diff --git a/man/intel_reg_dumper.man b/man/intel_reg_dumper.man new file mode 100644 index 00000000..89f6b9f9 --- /dev/null +++ b/man/intel_reg_dumper.man @@ -0,0 +1,33 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_reg_dumper __appmansuffix__ __xorgversion__ +.SH NAME +intel_reg_dumper \- Decode a bunch of Intel GPU registers for debugging +.SH SYNOPSIS +.B intel_reg_dumper [ options ] [ file ] +.SH DESCRIPTION +.B intel_reg_dumper +is a tool to read and decode the values of many Intel GPU registers. It is +commonly used in debugging video mode setting issues. If the +.B file +argument is present, the registers will be decoded from the given file +instead of the current registers. Use the +.B intel_reg_snapshot +tool to generate such files. + +When the +.B file +argument is present and the +.B -d +argument is not present, +.B intel_reg_dumper +will assume the file was generated on an Ironlake machine. +.SH OPTIONS +.TP +.B -d id +when a dump file is used, use 'id' as device id (in hex) +.TP +.B -h +prints a help message +.SH SEE ALSO +.BR intel_reg_snapshot(1) diff --git a/man/intel_reg_read.man b/man/intel_reg_read.man new file mode 100644 index 00000000..cc2bf612 --- /dev/null +++ b/man/intel_reg_read.man @@ -0,0 +1,15 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_reg_read __appmansuffix__ __xorgversion__ +.SH NAME +intel_reg_read \- Reads an Intel GPU register value +.SH SYNOPSIS +.B intel_reg_read \fIregister\fR +.SH DESCRIPTION +.B intel_reg_read +is a tool to read Intel GPU registers, for use in debugging. The +\fIregister\fR argument is given as hexadecimal. +.SH EXAMPLES +.TP +intel_reg_read 0x61230 +Shows the register value for the first internal panel fitter. diff --git a/man/intel_reg_snapshot.man b/man/intel_reg_snapshot.man new file mode 100644 index 00000000..1930f613 --- /dev/null +++ b/man/intel_reg_snapshot.man @@ -0,0 +1,15 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_reg_snapshot __appmansuffix__ __xorgversion__ +.SH NAME +intel_reg_snapshot \- Take a GPU register snapshot +.SH SYNOPSIS +.B intel_reg_snapshot +.SH DESCRIPTION +.B intel_reg_snapshot +takes a snapshot of the registers of an Intel GPU, and writes it to standard +output. These files can be inspected later with the +.B intel_reg_dumper +tool. +.SH SEE ALSO +.BR intel_reg_dumper(1) diff --git a/man/intel_reg_write.man b/man/intel_reg_write.man new file mode 100644 index 00000000..cb1731c6 --- /dev/null +++ b/man/intel_reg_write.man @@ -0,0 +1,16 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_reg_write __appmansuffix__ __xorgversion__ +.SH NAME +intel_reg_write \- Set an Intel GPU register to a value +.SH SYNOPSIS +.B intel_reg_write \fIregister\fR \fIvalue\fR +.SH DESCRIPTION +.B intel_reg_write +is a tool to set Intel GPU registers to values, for use in speeding up +debugging. The \fIregister\fR and \fIvalue\fR arguments are given as +hexadecimal. +.SH EXAMPLES +.TP +intel_reg_write 0x61230 0x0 +Disables the first internal panel fitter. diff --git a/man/intel_stepping.man b/man/intel_stepping.man new file mode 100644 index 00000000..fe172107 --- /dev/null +++ b/man/intel_stepping.man @@ -0,0 +1,15 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_stepping __appmansuffix__ __xorgversion__ +.SH NAME +intel_stepping \- Display the stepping information for an Intel GPU +.SH SYNOPSIS +.B intel_stepping +.SH DESCRIPTION +.B intel_stepping +is a tool to print the stepping information for an Intel GPU, along with +the PCI ID and revision used to determine it. +It requires root privilege to map the graphics device. +.SH BUGS +Not all the known stepping IDs or chipsets are included, so the output +on some devices may not be as specific as possible. diff --git a/man/intel_upload_blit_large.man b/man/intel_upload_blit_large.man new file mode 100644 index 00000000..9c75e1a1 --- /dev/null +++ b/man/intel_upload_blit_large.man @@ -0,0 +1,18 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_upload_blit_large __appmansuffix__ __xorgversion__ +.SH NAME +intel_upload_blit_large \- microbenchmark of Intel GPU performance +.SH SYNOPSIS +.nf +.B intel_upload_blit_large +.fi +.SH DESCRIPTION +.B intel_upload_blit_large +is a microbenchmark tool for DRM performance. It should be run with kernel +modesetting enabled, and may require root privilege for correct operation. +It does not require X to be running. +.PP +Given that it is a microbenchmark, its utility is largely for regression +testing of the kernel, and not for general conclusions on graphics +performance. diff --git a/man/intel_upload_blit_large_gtt.man b/man/intel_upload_blit_large_gtt.man new file mode 100644 index 00000000..fbe4623c --- /dev/null +++ b/man/intel_upload_blit_large_gtt.man @@ -0,0 +1,18 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_upload_blit_large_gtt __appmansuffix__ __xorgversion__ +.SH NAME +intel_upload_blit_large_gtt \- microbenchmark of Intel GPU performance +.SH SYNOPSIS +.nf +.B intel_upload_blit_large_gtt +.fi +.SH DESCRIPTION +.B intel_upload_blit_large_gtt +is a microbenchmark tool for DRM performance. It should be run with kernel +modesetting enabled, and may require root privilege for correct operation. +It does not require X to be running. +.PP +Given that it is a microbenchmark, its utility is largely for regression +testing of the kernel, and not for general conclusions on graphics +performance. diff --git a/man/intel_upload_blit_large_map.man b/man/intel_upload_blit_large_map.man new file mode 100644 index 00000000..04123f3d --- /dev/null +++ b/man/intel_upload_blit_large_map.man @@ -0,0 +1,18 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_upload_blit_large_map __appmansuffix__ __xorgversion__ +.SH NAME +intel_upload_blit_large_map \- microbenchmark of Intel GPU performance +.SH SYNOPSIS +.nf +.B intel_upload_blit_large_map +.fi +.SH DESCRIPTION +.B intel_upload_blit_large_map +is a microbenchmark tool for DRM performance. It should be run with kernel +modesetting enabled, and may require root privilege for correct operation. +It does not require X to be running. +.PP +Given that it is a microbenchmark, its utility is largely for regression +testing of the kernel, and not for general conclusions on graphics +performance. diff --git a/man/intel_upload_blit_small.man b/man/intel_upload_blit_small.man new file mode 100644 index 00000000..478bbfc5 --- /dev/null +++ b/man/intel_upload_blit_small.man @@ -0,0 +1,18 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel_upload_blit_small __appmansuffix__ __xorgversion__ +.SH NAME +intel_upload_blit_small \- microbenchmark of Intel GPU performance +.SH SYNOPSIS +.nf +.B intel_upload_blit_small +.fi +.SH DESCRIPTION +.B intel_upload_blit_small +is a microbenchmark tool for DRM performance. It should be run with kernel +modesetting enabled, and may require root privilege for correct operation. +It does not require X to be running. +.PP +Given that it is a microbenchmark, its utility is largely for regression +testing of the kernel, and not for general conclusions on graphics +performance. diff --git a/packaging/intel-gpu-tools.changes b/packaging/intel-gpu-tools.changes new file mode 100644 index 00000000..d0f8a262 --- /dev/null +++ b/packaging/intel-gpu-tools.changes @@ -0,0 +1,5 @@ +* Fri Jan 25 2013 Geoffroy Van Cutsem <geoffroy.vancutsem@intel.com> intel-gpu-tools-1.3 +- Initial release to Tizen +- custom .gbs.conf file +- packaging information + diff --git a/packaging/intel-gpu-tools.spec b/packaging/intel-gpu-tools.spec new file mode 100644 index 00000000..596dbd3e --- /dev/null +++ b/packaging/intel-gpu-tools.spec @@ -0,0 +1,36 @@ +Name: intel-gpu-tools +Summary: Diagnositc tools for Intel Integrated Graphics +Version: 1.3 +Release: 1 +VCS: git/xorg/app/intel-gpu-tools.git#intel-gpu-tools-1.3-1-g24e49c7 +Group: Development/Tools +License: MIT +URL: http://xorg.freedesktop.org/ +Source0: http://xorg.freedesktop.org/archive/individual/app/intel-gpu-tools-%{version}.tar.bz2 +BuildRequires: pkgconfig(libdrm_intel) +BuildRequires: pkgconfig(pciaccess) +BuildRequires: pkgconfig(xorg-macros) +BuildRequires: pkgconfig(cairo) +BuildRequires: pkgconfig(libudev) + +%description +Description: %{summary} + +%prep +%setup -q -n %{name}-%{version} + +%build +%reconfigure --disable-static \ + --disable-nouveau +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install + +%files +%defattr(-,root,root,-) +%doc README +%{_bindir}/* +%doc %{_mandir}/man1/*.1.gz + diff --git a/scripts/Makefile.am b/scripts/Makefile.am new file mode 100644 index 00000000..baf3612e --- /dev/null +++ b/scripts/Makefile.am @@ -0,0 +1,3 @@ + +dist_noinst_SCRIPTS = who.sh +noinst_PYTHON = throttle.py diff --git a/scripts/convert_itp.py b/scripts/convert_itp.py new file mode 100755 index 00000000..4474f34d --- /dev/null +++ b/scripts/convert_itp.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 + +#this script helps to convert internal debugger scripts given to us into our tools + +import sys +import fileinput + +def replace_with_dict(text, dicto): + for key, val in dicto.items(): + text = text.replace(key, val) + return text + +for lines in fileinput.input([sys.argv[1]], inplace=True): + lines = lines.strip() + if lines == '': continue # strip empty lines + replace_dict = {'dword(' : '../tools/intel_reg_read ', 'MMADDR + ' : '', '//' : '#', ')p;' : '', ')p ' : ' -c '} + print(replace_with_dict(lines, replace_dict)) diff --git a/scripts/display_debug.sh b/scripts/display_debug.sh new file mode 100755 index 00000000..f854f90b --- /dev/null +++ b/scripts/display_debug.sh @@ -0,0 +1,172 @@ +#!/bin/bash + +# FBC_CFB_BASE 0x43200 +../tools/intel_reg_read 0x43200 +# FBC_CTL 0x43208 +../tools/intel_reg_read 0x43208 +# ERR_INT 0x44040 +../tools/intel_reg_read 0x44040 +# DE_RRMR 0x44050 +../tools/intel_reg_read 0x44050 +# ARB_CTL 0x45000 +../tools/intel_reg_read 0x45000 +# ARB_CTL2 0x45004 +../tools/intel_reg_read 0x45004 +# MSG_CTL 0x45010 +../tools/intel_reg_read 0x45010 +# Watermarks +../tools/intel_reg_read 0x45100 +../tools/intel_reg_read 0x45104 +../tools/intel_reg_read 0x45200 +../tools/intel_reg_read 0x45108 +../tools/intel_reg_read 0x4510C +../tools/intel_reg_read 0x45110 +../tools/intel_reg_read 0x45120 +../tools/intel_reg_read 0x45124 +../tools/intel_reg_read 0x45128 +# Pipe A timing 0x60000-0x6004C +../tools/intel_reg_read 0x60000 -c 0x13; +# Pipe B timing 0x61000-0x6104C +../tools/intel_reg_read 0x61000 -c 0x13; +# Pipe C timing 0x62000-0x6204C +../tools/intel_reg_read 0x62000 -c 0x13; +# FDI A 0x60100 +# FDI B 0x61100 +# FDI C 0x62100 +# EDP 0x64000 +../tools/intel_reg_read 0x60100 +../tools/intel_reg_read 0x61100 +../tools/intel_reg_read 0x62100 +../tools/intel_reg_read 0x64000 +# Panel fitter A window size 0x68074 +# Panel fitter A control 0x68080 +../tools/intel_reg_read 0x68074 +../tools/intel_reg_read 0x68080 +# Panel fitter B window size 0x68874 +# Panel fitter B control 0x68880 +../tools/intel_reg_read 0x68874 +../tools/intel_reg_read 0x68880 +# Panel fitter C window size 0x69074 +# Panel fitter C control 0x69080 +../tools/intel_reg_read 0x69074 +../tools/intel_reg_read 0x69080 +# Pipe A config 0x70008 +# Pipe B config 0x71008 +# Pipe C config 0x72008 +../tools/intel_reg_read 0x70008 +../tools/intel_reg_read 0x71008 +../tools/intel_reg_read 0x72008 +# Cursor A control 0x70080 +# Cursor B control 0x71080 +# Cursor C control 0x72080 +../tools/intel_reg_read 0x70080 +../tools/intel_reg_read 0x71080 +../tools/intel_reg_read 0x72080 +# Primary A control 0x70180 +# Primary B control 0x71180 +# Primary C control 0x72180 +../tools/intel_reg_read 0x70180 +../tools/intel_reg_read 0x71180 +../tools/intel_reg_read 0x72180 +# Sprite A control 0x70280 +# Sprite B control 0x71280 +# Sprite C control 0x72280 +../tools/intel_reg_read 0x70280 +../tools/intel_reg_read 0x71280 +../tools/intel_reg_read 0x72280 +# Sprite A size 0x70290 +# Sprite B size 0x71290 +# Sprite C size 0x72290 +../tools/intel_reg_read 0x70290 +../tools/intel_reg_read 0x71290 +../tools/intel_reg_read 0x72290 +# Sprite A scaling 0x70304 +# Sprite B scaling 0x71304 +# Sprite C scaling 0x72304 +../tools/intel_reg_read 0x70304 +../tools/intel_reg_read 0x71304 +../tools/intel_reg_read 0x72304 +# PCH DE Interrupt enable 0xC400C +../tools/intel_reg_read 0xC400C +# PCH DE Interrupt IIR 0xC4008 +../tools/intel_reg_read 0xC4008 +# PCH DE hotplug 0xC4030 +../tools/intel_reg_read 0xC4030 +# SERR_INT 0xC4040 +../tools/intel_reg_read 0xC4040 +# PCH DPLL A CTL 0xC6014 +# PCH DPLL A Divisor 0 0xC6040 +# PCH DPLL A Divisor 1 0xC6044 +../tools/intel_reg_read 0xC6014 +../tools/intel_reg_read 0xC6040 +../tools/intel_reg_read 0xC6044 +# PCH DPLL B CTL 0xC6018 +# PCH DPLL B Divisor 0 0xC6048 +# PCH DPLL B Divisor 1 0xC604C +../tools/intel_reg_read 0xC6018 +../tools/intel_reg_read 0xC6048 +../tools/intel_reg_read 0xC604C +# PCH DPLL DREF CTL 0xC6200 +../tools/intel_reg_read 0xC6200 +# PCH DPLL SEL 0xC7000 +../tools/intel_reg_read 0xC7000 +# PCH Panel Status 0xC7200 +../tools/intel_reg_read 0xC7200 +# PCH Panel Control 0xC7204 +../tools/intel_reg_read 0xC7204 +# Transcoder A timing 0xE0000-0xE004F +# Transcoder B timing 0xE1000-0xE104F +# Transcoder C timing 0xE2000-0xE204F +../tools/intel_reg_read 0xE0000 -c 0x14; +../tools/intel_reg_read 0xE1000 -c 0x14; +../tools/intel_reg_read 0xE2000 -c 0x14; +# Transcoder A DP CTL 0xE0300 +# Transcoder B DP CTL 0xE1300 +# Transcoder C DP CTL 0xE2300 +../tools/intel_reg_read 0xE0300 +../tools/intel_reg_read 0xE1300 +../tools/intel_reg_read 0xE2300 +# CRT DAC CTL 0xE1100 +../tools/intel_reg_read 0xE1100 +# HDMI/DVI B CTL 0xE1140 +# HDMI/DVI C CTL 0xE1150 +# HDMI/DVI D CTL 0xE1160 +../tools/intel_reg_read 0xE1140 +../tools/intel_reg_read 0xE1150 +../tools/intel_reg_read 0xE1160 +# LVDS 0xE1180 +../tools/intel_reg_read 0xE1180 +# DP B CTL 0xE4100 +# DP C CTL 0xE4200 +# DP D CTL 0xE4300 +../tools/intel_reg_read 0xE4100 +../tools/intel_reg_read 0xE4200 +../tools/intel_reg_read 0xE4300 +# Transcoder A config 0xF0008 +# FDI RX A CTL 0xF000C +# FDI RX A MISC 0xF0010 +# FDI RX A IIR 0xF0014 +# FDI RX A IMR 0xF0018 +../tools/intel_reg_read 0xF0008 -c 5; +# Transcoder B config 0xF1008 +# FDI RX B CTL 0xF100C +# FDI RX B MISC 0xF1010 +# FDI RX B IIR 0xF1014 +# FDI RX B IMR 0xF1018 +../tools/intel_reg_read 0xF1008 -c 5; +# Transcoder C config 0xF2008 +# FDI RX C CTL 0xF200C +# FDI RX C MISC 0xF2010 +# FDI RX C IIR 0xF2014 +# FDI RX C IMR 0xF2018 +../tools/intel_reg_read 0xF2008 -c 5; +#Check if frame and line counters are running +../tools/intel_reg_read 0x44070 +../tools/intel_reg_read 0x70050 +../tools/intel_reg_read 0x71050 +../tools/intel_reg_read 0x72050 +sleep 2; +../tools/intel_reg_read 0x44070 +../tools/intel_reg_read 0x70050 +../tools/intel_reg_read 0x71050 +../tools/intel_reg_read 0x72050 diff --git a/scripts/throttle.py b/scripts/throttle.py new file mode 100755 index 00000000..126175ca --- /dev/null +++ b/scripts/throttle.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# +# Usage: +# scripts/throttle.py trace-dat +# +# Shows how often the trace throttles and for how long. + +import getopt +from tracecmd import * +import sys + +requests = {} +throttle = {} +prev_throttle = 0; + +def read_events(t): + for cpu in range(0, t.cpus): + e = t.read_event(cpu) + while e: + if e.name == 'i915_gem_request_complete': + seqno = e.num_field('seqno') + requests[seqno] = e.ts; + + if e.name == 'i915_gem_request_throttle_begin': + seqno = e.num_field('seqno') + throttle[seqno] = e.ts + + if e.name == 'i915_gem_request_throttle_end': + global prev_throttle + + ts = 0 + sum_dispatch = 0 + num_dispatch = 0 + max_dispatch = 0 + + seqno = e.num_field('seqno') + s = prev_throttle + if s == 0: + s = seqno + while s <= seqno: + if requests.has_key(s): + if ts: + delta = requests[s] - ts + num_dispatch += 1 + sum_dispatch += delta + if delta > max_dispatch: max_dispatch = delta + ts = requests[s] + s += 1 + + if throttle.has_key(seqno) and throttle.has_key(prev_throttle) and num_dispatch: + print "throttle +%d: %dms -- %d dispatch, avg %.3fms, max %dus" % ((throttle[seqno]-throttle[prev_throttle])/1000000, (e.ts - throttle[seqno]) / 1000000, num_dispatch, sum_dispatch / (1000000. * num_dispatch), max_dispatch / 1000) + throttle[seqno] = e.ts + + prev_throttle = seqno + + e = t.read_event(cpu) + +if __name__ == "__main__": + if len(sys.argv) >=2: + filename = sys.argv[1] + else: + filename = "trace.dat" + + print "Initializing trace '%s'..." % (filename) + trace = Trace(filename) + read_events(trace) + diff --git a/scripts/who.sh b/scripts/who.sh new file mode 100755 index 00000000..b2216398 --- /dev/null +++ b/scripts/who.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# usage: sudo who.sh +# +# Requires root permissions to both query who has the device open, +# and to read the mappings of likely root-owned processes +# + +for i in `lsof -t /dev/dri/card0`; do + who=`readlink /proc/$i/exe` + count=`grep /dev/dri/card0 /proc/$i/maps | wc -l | cut -f1 -d\ ` + echo "$who [$i]: $count" +done diff --git a/shaders/ps/README b/shaders/ps/README new file mode 100644 index 00000000..b196d025 --- /dev/null +++ b/shaders/ps/README @@ -0,0 +1 @@ +These files are here for reference only. diff --git a/shaders/ps/blit.g7a b/shaders/ps/blit.g7a new file mode 100644 index 00000000..deeedcc5 --- /dev/null +++ b/shaders/ps/blit.g7a @@ -0,0 +1,66 @@ +/* Assemble with ".../intel-gen4asm/src/intel-gen4asm -g 7" */ + + +/* Move pixels into g10-g13. The pixel shaader does not load what you want. It + * loads the input data for a plane function to calculate what you want. The + * following is boiler plate code to move our normalized texture coordinates + * (u,v) into g10-g13. It does this 4 subspans (16 pixels) at a time. + * + * This should do the same thing, but it doesn't work for some reason. + * pln(16) g10 g6<0,1,0>F g2<8,8,1>F { align1 }; + * pln(16) g12 g6.16<1>F g2<8,8,1>F { align1 }; + */ +/* U */ +pln (8) g10<1>F g6.0<0,1,0>F g2.0<8,8,1>F { align1 }; /* pixel 0-7 */ +pln (8) g11<1>F g6.0<0,1,0>F g4.0<8,8,1>F { align1 }; /* pixel 8-15 */ +/* V */ +pln (8) g12<1>F g6.16<0,1,0> g2.0<8,8,1>F { align1 }; /* pixel 0-7 */ +pln (8) g13<1>F g6.16<0,1,0> g4.0<8,8,1>F { align1 }; /* pixel 8-15 */ + + +/* Next the we want the sampler to fetch the src texture (ie. src buffer). This + * is done with a pretty simple send message. The output goes to g112, which is + * exactly what we're supposed to use in our final send message. + * In intel-gen4asm, we should end up parsed by the following rule: + * predicate SEND execsize dst sendleadreg sndopr directsrcoperand instoptions + * + * Send message descriptor: + * 28:25 = message len = 4 // our 4 registers have 16 pixels + * 24:20 = response len = 8 // Each pixel is RGBA32, so we need 8 registers + * 19:19 = header present = 0 + * 18:17 = SIMD16 = 2 + * 16:12 = TYPE = 0 (regular sample) + * 11:08 = Sampler index = ignored/0 + * 7:0 = binding table index = src = 1 + * 0x8840001 + * + * Send message extra descriptor + * 5:5 = End of Thread = 0 + * 3:0 = Target Function ID = SFID_SAMPLER (2) + * 0x2 + */ + +send(16) g112 g10 0x2 0x8840001 { align1 }; + +/* g112-g119 now contains the sample source input, and all we must do is write + * it out to the destination render target. This is done with the send message + * as well. The only extra bits are to terminate the pixel shader. + * + * Send message descriptor: + * 28:25 = message len = 8 // 16 pixels RGBA32 + * 24:20 = response len = 0 + * 19:19 = header present = 0 + * 17:14 = message type = Render Target Write (12) + * 12:12 = Last Render Target Select = 1 + * 10:08 = Message Type = SIMD16 (0) + * 07:00 = Binding Table Index = dest = 0 + * 0x10031000 + * + * Send message extra descriptor + * 5:5 = End of Thread = 1 + * 3:0 = Target Function ID = SFID_DP_RC (5) + * 0x25 + */ +send(16) null g112 0x25 0x10031000 { align1, EOT }; + +/* vim: set ft=c ts=4 sw=2 tw=80 et: */ diff --git a/shaders/ps/neg1_test.g7a b/shaders/ps/neg1_test.g7a new file mode 100644 index 00000000..744a7690 --- /dev/null +++ b/shaders/ps/neg1_test.g7a @@ -0,0 +1,9 @@ +mov(8) g112:UD 0x3f800000:UD { align1 }; +mov(8) g113:UD 0x3f800000:UD { align1 }; +mov(8) g114:UD 0x3f800000:UD { align1 }; +mov(8) g115:UD 0x3f800000:UD { align1 }; +mov(8) g116:UD 0x3f800000:UD { align1 }; +mov(8) g117:UD 0x3f800000:UD { align1 }; +mov(8) g118:UD 0x3f800000:UD { align1 }; +mov(8) g119:UD 0x3f800000:UD { align1 }; +send(16) null g112 0x25 0x10031000 { align1, EOT }; diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 00000000..1a6795bc --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,78 @@ +flip_test +drm_vma_limiter +drm_vma_limiter_cached +drm_vma_limiter_cpu +drm_vma_limiter_gtt +gem_bad_address +gem_bad_batch +gem_bad_blit +gem_bad_length +gem_basic +gem_cs_prefetch +gem_cpu_concurrent_blit +gem_ctx_bad_destroy +gem_ctx_bad_exec +gem_ctx_basic +gem_ctx_create +gem_ctx_exec +gem_double_irq_loop +gem_dummy_reloc_loop +gem_exec_bad_domains +gem_exec_blt +gem_exec_faulting_reloc +gem_exec_nop +gem_fenced_exec_thrash +gem_fence_thrash +gem_flink +gem_gtt_speed +gem_gtt_concurrent_blit +gem_gtt_cpu_tlb +gem_hang +gem_hangcheck_forcewake +gem_largeobject +gem_linear_blits +gem_mmap +gem_mmap_gtt +gem_mmap_offset_exhaustion +gem_partial_pwrite_pread +gem_pipe_control_store_loop +gem_pread_after_blit +gem_pwrite +gem_readwrite +gem_reloc_vs_gpu +gem_reg_read +gem_ringfill +gem_ring_sync_loop +gem_set_tiling_vs_blt +gem_set_tiling_vs_gtt +gem_set_tiling_vs_pwrite +gem_storedw_batches_loop +gem_storedw_loop_blt +gem_storedw_loop_bsd +gem_storedw_loop_render +gem_stress +gem_tiled_blits +gem_tiled_fence_blits +gem_tiled_partial_pwrite_pread +gem_tiled_pread +gem_tiled_pread_pwrite +gem_tiled_swapping +gem_unfence_active_buffers +gem_unref_active_buffers +gem_vmap_blits +gem_wait_render_timeout +gen3_mixed_blits +gen3_render_linear_blits +gen3_render_mixed_blits +gen3_render_tiledx_blits +gen3_render_tiledy_blits +getclient +getstats +getversion +prime_nv_api +prime_nv_pcopy +prime_nv_test +prime_self_import +testdisplay +sysfs_rc6_residency +# Please keep sorted alphabetically diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 00000000..e29a383a --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,148 @@ +noinst_PROGRAMS = \ + gem_stress \ + $(TESTS_progs) \ + $(HANG) \ + $(NULL) + +if HAVE_NOUVEAU +NOUVEAU_TESTS = \ + prime_nv_api \ + prime_nv_pcopy \ + prime_nv_test +endif + +TESTS_progs = \ + getversion \ + getclient \ + getstats \ + gem_basic \ + gem_cpu_concurrent_blit \ + gem_gtt_concurrent_blit \ + gem_exec_nop \ + gem_exec_blt \ + gem_exec_bad_domains \ + gem_exec_faulting_reloc \ + gem_flink \ + gem_readwrite \ + gem_ringfill \ + gem_mmap \ + gem_mmap_gtt \ + gem_mmap_offset_exhaustion \ + gem_pwrite \ + gem_pread_after_blit \ + gem_set_tiling_vs_blt \ + gem_set_tiling_vs_gtt \ + gem_set_tiling_vs_pwrite \ + gem_tiled_pread \ + gem_tiled_pread_pwrite \ + gem_tiled_partial_pwrite_pread \ + gem_tiled_swapping \ + gem_partial_pwrite_pread \ + gem_linear_blits \ + gem_vmap_blits \ + gem_tiled_blits \ + gem_tiled_fence_blits \ + gem_largeobject \ + gem_bad_length \ + gem_fence_thrash \ + gem_fenced_exec_thrash \ + gem_gtt_speed \ + gem_gtt_cpu_tlb \ + gem_cs_prefetch \ + gen3_render_linear_blits \ + gen3_render_tiledx_blits \ + gen3_render_tiledy_blits \ + gen3_render_mixed_blits \ + gen3_mixed_blits \ + gem_storedw_loop_render \ + gem_storedw_loop_blt \ + gem_storedw_loop_bsd \ + gem_storedw_batches_loop \ + gem_dummy_reloc_loop \ + gem_double_irq_loop \ + gem_ring_sync_loop \ + gem_pipe_control_store_loop \ + gem_unfence_active_buffers \ + gem_unref_active_buffers \ + gem_reloc_vs_gpu \ + drm_vma_limiter \ + drm_vma_limiter_cpu \ + drm_vma_limiter_gtt \ + drm_vma_limiter_cached \ + sysfs_rc6_residency \ + flip_test \ + gem_wait_render_timeout \ + gem_ctx_create \ + gem_ctx_bad_destroy \ + gem_ctx_exec \ + gem_ctx_bad_exec \ + gem_ctx_basic \ + gem_reg_read \ + $(NOUVEAU_TESTS) \ + prime_self_import \ + $(NULL) + +# IMPORTANT: The ZZ_ tests need to be run last! +# ... and make can't deal with inlined comments ... +TESTS_scripts = \ + debugfs_reader \ + debugfs_emon_crash \ + sysfs_l3_parity \ + sysfs_edid_timing \ + module_reload \ + ZZ_check_dmesg \ + ZZ_hangman \ + $(NULL) + +kernel_tests = \ + $(TESTS_progs) \ + $(TESTS_scripts) \ + $(NULL) + +TESTS = \ + $(NULL) + +test: + whoami | grep root || ( echo ERROR: not running as root; exit 1 ) + ./check_drm_clients + make TESTS="${kernel_tests}" check + +HANG = \ + gem_bad_batch \ + gem_hang \ + gem_bad_blit \ + gem_bad_address \ + $(NULL) + +EXTRA_PROGRAMS = $(TESTS_progs) $(HANG) +EXTRA_DIST = $(TESTS_scripts) drm_lib.sh check_drm_clients debugfs_wedged +CLEANFILES = $(EXTRA_PROGRAMS) + +AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) \ + -I$(srcdir)/.. \ + -I$(srcdir)/../lib +LDADD = ../lib/libintel_tools.la $(PCIACCESS_LIBS) $(DRM_LIBS) + +testdisplay_SOURCES = \ + testdisplay.c \ + testdisplay.h \ + testdisplay_hotplug.c \ + $(NULL) + +TESTS_progs += testdisplay +LDADD += $(CAIRO_LIBS) $(LIBUDEV_LIBS) $(GLIB_LIBS) +AM_CFLAGS += $(CAIRO_CFLAGS) $(LIBUDEV_CFLAGS) $(GLIB_CFLAGS) + +gem_fence_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS) +gem_fence_thrash_LDADD = $(LDADD) -lpthread + +gem_wait_render_timeout_LDADD = $(LDADD) -lrt + +gem_ctx_basic_LDADD = $(LDADD) -lpthread + +prime_nv_test_CFLAGS = $(AM_CFLAGS) $(DRM_NOUVEAU_CFLAGS) +prime_nv_test_LDADD = $(LDADD) $(DRM_NOUVEAU_LIBS) +prime_nv_api_CFLAGS = $(AM_CFLAGS) $(DRM_NOUVEAU_CFLAGS) +prime_nv_api_LDADD = $(LDADD) $(DRM_NOUVEAU_LIBS) +prime_nv_pcopy_CFLAGS = $(AM_CFLAGS) $(DRM_NOUVEAU_CFLAGS) +prime_nv_pcopy_LDADD = $(LDADD) $(DRM_NOUVEAU_LIBS) diff --git a/tests/ZZ_check_dmesg b/tests/ZZ_check_dmesg new file mode 100755 index 00000000..e28ba35f --- /dev/null +++ b/tests/ZZ_check_dmesg @@ -0,0 +1,11 @@ +#!/bin/sh + +if dmesg | grep '\*ERROR\*' > /dev/null ; then + echo "DRM_ERROR dirt in dmesg" + exit 1 +fi + +if dmesg | grep -- '------\[ cut here \]----' > /dev/null ; then + echo "found a backtrace in dmesg" + exit 1 +fi diff --git a/tests/ZZ_hangman b/tests/ZZ_hangman new file mode 100755 index 00000000..b8f4a682 --- /dev/null +++ b/tests/ZZ_hangman @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Testcase: Simulate gpu hang +# +# This check uses the stop_rings facility to exercise the gpu hang code. +# by reading /sys/kernel/debug/dri/0/i915_emon_status too quickly +# + +SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )" +. $SOURCE_DIR/drm_lib.sh + +oldpath=`pwd` + +cd $i915_path + +if [ ! -f i915_ring_stop ] ; then + echo "kernel doesn't support ring stopping" + exit 77 +fi + +if cat i915_error_state | grep -v "no error state collected" > /dev/null ; then + echo "gpu hang dectected" + exit 1 +fi + +# stop rings +echo 0xf > i915_ring_stop +echo "rings stopped" + +(cd $oldpath; $SOURCE_DIR/gem_exec_nop) > /dev/null + +if cat i915_error_state | grep -v "no error state collected" > /dev/null ; then + echo "gpu hang correctly dectected" +else + echo "gpu hang not dectected" + exit 2 +fi + +# clear error state +echo > i915_error_state + +exit 0 diff --git a/tests/check_drm_clients b/tests/check_drm_clients new file mode 100755 index 00000000..eb12416a --- /dev/null +++ b/tests/check_drm_clients @@ -0,0 +1,6 @@ +#!/bin/bash + +SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )" +. $SOURCE_DIR/drm_lib.sh + +exit 0 diff --git a/tests/debugfs_emon_crash b/tests/debugfs_emon_crash new file mode 100755 index 00000000..6e139a41 --- /dev/null +++ b/tests/debugfs_emon_crash @@ -0,0 +1,16 @@ +#!/bin/bash +# +# This check if we can crash the kernel with segmentation-fault +# by reading /sys/kernel/debug/dri/0/i915_emon_status too quickly +# + +SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )" +. $SOURCE_DIR/drm_lib.sh + +for z in $(seq 1 1000); do + cat $i915_path/i915_emon_status > /dev/null 2&>1 +done + +# If we got here, we haven't crashed + +exit 0 diff --git a/tests/debugfs_reader b/tests/debugfs_reader new file mode 100755 index 00000000..80d59988 --- /dev/null +++ b/tests/debugfs_reader @@ -0,0 +1,9 @@ +#!/bin/bash + +SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )" +. $SOURCE_DIR/drm_lib.sh + +# read everything we can +cat $i915_path/* > /dev/null 2>&1 + +exit 0 diff --git a/tests/debugfs_wedged b/tests/debugfs_wedged new file mode 100755 index 00000000..80a32f61 --- /dev/null +++ b/tests/debugfs_wedged @@ -0,0 +1,10 @@ +#!/bin/sh + +SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )" +. $SOURCE_DIR/drm_lib.sh + +# Testcase: wedge the hw to check the error_state reading +# +# Unfortunately wedged is permanent, so this test is not run by default +echo 1 > ${i915_path}/i915_wedged +cat $i915_path/i915_error_state > /dev/null 2>&1 diff --git a/tests/drm_lib.sh b/tests/drm_lib.sh new file mode 100755 index 00000000..a76fd474 --- /dev/null +++ b/tests/drm_lib.sh @@ -0,0 +1,32 @@ +#!/bin/sh +die() { + echo "$@" + exit 1 +} + +if [ -d /debug/dri ] ; then + debugfs_path=/debug/dri +fi + +if [ -d /sys/kernel/debug/dri ] ; then + debugfs_path=/sys/kernel/debug/dri +fi + +i915_path=x +for dir in `ls $debugfs_path` ; do + if [ -f $debugfs_path/$dir/i915_error_state ] ; then + i915_path=$debugfs_path/$dir + break + fi +done + +if [ $i915_path = "x" ] ; then + die " i915 debugfs path not found." +fi + +# read everything we can +if [ `cat $i915_path/clients | wc -l` -gt "2" ] ; then + die "ERROR: other drm clients running" +fi + + diff --git a/tests/drm_vma_limiter.c b/tests/drm_vma_limiter.c new file mode 100644 index 00000000..1971e2dc --- /dev/null +++ b/tests/drm_vma_limiter.c @@ -0,0 +1,110 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +/* Testcase: check whether the libdrm vma limiter works + * + * We've had reports of the X server exhausting the default rlimit of 64k vma's + * in the kernel. libdrm has grown facilities to limit the vma caching since, + * this checks whether they actually work. + */ + +/* we do both cpu and gtt maps, so only need half of 64k to exhaust */ +#define BO_ARRAY_SIZE 35000 +drm_intel_bo *bos[BO_ARRAY_SIZE]; + +int main(int argc, char **argv) +{ + int fd; + int i; + char *ptr; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + drm_intel_bufmgr_gem_set_vma_cache_size(bufmgr, 500); + + for (i = 0; i < BO_ARRAY_SIZE; i++) { + bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096); + assert(bos[i]); + + drm_intel_bo_map(bos[i], 1); + ptr = bos[i]->virtual; + assert(ptr); + *ptr = 'c'; + drm_intel_bo_unmap(bos[i]); + + drm_intel_gem_bo_map_gtt(bos[i]); + ptr = bos[i]->virtual; + assert(ptr); + *ptr = 'c'; + drm_intel_gem_bo_unmap_gtt(bos[i]); + } + + /* and recheck whether a second map of the same still works */ + for (i = 0; i < BO_ARRAY_SIZE; i++) { + bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096); + assert(bos[i]); + + drm_intel_bo_map(bos[i], 1); + ptr = bos[i]->virtual; + assert(*ptr = 'c'); + drm_intel_bo_unmap(bos[i]); + + drm_intel_gem_bo_map_gtt(bos[i]); + ptr = bos[i]->virtual; + assert(*ptr = 'c'); + drm_intel_gem_bo_unmap_gtt(bos[i]); + } + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/drm_vma_limiter_cached.c b/tests/drm_vma_limiter_cached.c new file mode 100644 index 00000000..37976185 --- /dev/null +++ b/tests/drm_vma_limiter_cached.c @@ -0,0 +1,138 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +/* Testcase: check whether the libdrm vma limiter works + * + * We've had reports of the X server exhausting the default rlimit of 64k vma's + * in the kernel. libdrm has grown facilities to limit the vma caching since, + * this checks whether they actually work. + * + * This one checks whether mmaps of unused cached bos are also properly reaped. + */ + +/* we do both cpu and gtt maps, so only need half of 64k to exhaust */ + +int main(int argc, char **argv) +{ + int fd; + int i; + char *ptr; + drm_intel_bo *load_bo; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + load_bo = drm_intel_bo_alloc(bufmgr, "target bo", 1024*4096, 4096); + assert(load_bo); + + drm_intel_bufmgr_gem_set_vma_cache_size(bufmgr, 500); + + /* IMPORTANT: we need to enable buffer reuse, otherwise we won't test + * the libdrm bo cache! */ + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + /* put some load onto the gpu to keep the light buffers active for long + * enough */ + for (i = 0; i < 10000; i++) { + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + 4096); + OUT_BATCH(0); /* dst x1,y1 */ + OUT_BATCH((1024 << 16) | 512); + OUT_RELOC(load_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH((0 << 16) | 512); /* src x1, y1 */ + OUT_BATCH(4096); + OUT_RELOC(load_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + } + +#define GROUP_SZ 100 + for (i = 0; i < 68000; ) { + int j; + drm_intel_bo *bo[GROUP_SZ]; + + for (j = 0; j < GROUP_SZ; j++, i++) { + bo[j] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096); + assert(bo[j]); + + drm_intel_gem_bo_map_gtt(bo[j]); + ptr = bo[j]->virtual; + assert(ptr); + *ptr = 'c'; + drm_intel_gem_bo_unmap_gtt(bo[j]); + + /* put it onto the active list ... */ + BEGIN_BATCH(6); + OUT_BATCH(XY_COLOR_BLT_CMD | + XY_COLOR_BLT_WRITE_ALPHA | + XY_COLOR_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + 128); + OUT_BATCH(0); /* dst x1,y1 */ + OUT_BATCH((1 << 16) | 1); + OUT_RELOC(bo[j], I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0xffffffff); /* color */ + ADVANCE_BATCH(); + } + intel_batchbuffer_flush(batch); + + for (j = 0; j < GROUP_SZ; j++) + drm_intel_bo_unreference(bo[j]); + } + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/drm_vma_limiter_cpu.c b/tests/drm_vma_limiter_cpu.c new file mode 100644 index 00000000..24ce188e --- /dev/null +++ b/tests/drm_vma_limiter_cpu.c @@ -0,0 +1,100 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +/* Testcase: check whether the libdrm vma limiter works + * + * We've had reports of the X server exhausting the default rlimit of 64k vma's + * in the kernel. libdrm has grown facilities to limit the vma caching since, + * this checks whether they actually work. + * + * This one checks cpu mmaps only. + */ + +#define BO_ARRAY_SIZE 68000 +drm_intel_bo *bos[BO_ARRAY_SIZE]; + +int main(int argc, char **argv) +{ + int fd; + int i; + char *ptr; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + drm_intel_bufmgr_gem_set_vma_cache_size(bufmgr, 500); + + for (i = 0; i < BO_ARRAY_SIZE; i++) { + bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096); + assert(bos[i]); + + drm_intel_bo_map(bos[i], 1); + ptr = bos[i]->virtual; + assert(ptr); + *ptr = 'c'; + drm_intel_bo_unmap(bos[i]); + } + + /* and recheck whether a second map of the same still works */ + for (i = 0; i < BO_ARRAY_SIZE; i++) { + bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096); + assert(bos[i]); + + drm_intel_bo_map(bos[i], 1); + ptr = bos[i]->virtual; + assert(*ptr = 'c'); + drm_intel_bo_unmap(bos[i]); + } + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/drm_vma_limiter_gtt.c b/tests/drm_vma_limiter_gtt.c new file mode 100644 index 00000000..540ea917 --- /dev/null +++ b/tests/drm_vma_limiter_gtt.c @@ -0,0 +1,101 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +/* Testcase: check whether the libdrm vma limiter works + * + * We've had reports of the X server exhausting the default rlimit of 64k vma's + * in the kernel. libdrm has grown facilities to limit the vma caching since, + * this checks whether they actually work. + * + * This one checks cpu mmaps only. + */ + +/* we do both cpu and gtt maps, so only need half of 64k to exhaust */ +#define BO_ARRAY_SIZE 68000 +drm_intel_bo *bos[BO_ARRAY_SIZE]; + +int main(int argc, char **argv) +{ + int fd; + int i; + char *ptr; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + drm_intel_bufmgr_gem_set_vma_cache_size(bufmgr, 500); + + for (i = 0; i < BO_ARRAY_SIZE; i++) { + bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096); + assert(bos[i]); + + drm_intel_gem_bo_map_gtt(bos[i]); + ptr = bos[i]->virtual; + assert(ptr); + *ptr = 'c'; + drm_intel_gem_bo_unmap_gtt(bos[i]); + } + + /* and recheck whether a second map of the same still works */ + for (i = 0; i < BO_ARRAY_SIZE; i++) { + bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096); + assert(bos[i]); + + drm_intel_gem_bo_map_gtt(bos[i]); + ptr = bos[i]->virtual; + assert(*ptr = 'c'); + drm_intel_gem_bo_unmap_gtt(bos[i]); + } + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/flip_test.c b/tests/flip_test.c new file mode 100644 index 00000000..67105905 --- /dev/null +++ b/tests/flip_test.c @@ -0,0 +1,317 @@ +/* + * Copyright 2012 Intel Corporation + * Jesse Barnes <jesse.barnes@intel.com> + * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS 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 "config.h" + +#include <assert.h> +#include <cairo.h> +#include <errno.h> +#include <math.h> +#include <stdint.h> +#include <unistd.h> +#include <sys/poll.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/ioctl.h> + +#include "i915_drm.h" +#include "drmtest.h" +#include "testdisplay.h" + +drmModeRes *resources; +int drm_fd; +int test_time = 3; + +uint32_t *fb_ptr; + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct type_name { + int type; + const char *name; +}; + +struct test_output { + uint32_t id; + int mode_valid; + drmModeModeInfo mode; + drmModeEncoder *encoder; + drmModeConnector *connector; + int crtc; + int pipe; + unsigned int current_fb_id; + unsigned int fb_ids[2]; +}; + +static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, + unsigned int usec, void *data) +{ + struct test_output *o = data; + unsigned int new_fb_id; + + if (o->current_fb_id == o->fb_ids[0]) + new_fb_id = o->fb_ids[1]; + else + new_fb_id = o->fb_ids[0]; + + drmModePageFlip(drm_fd, o->crtc, new_fb_id, + DRM_MODE_PAGE_FLIP_EVENT, o); + o->current_fb_id = new_fb_id; +} + +static void connector_find_preferred_mode(struct test_output *o, int crtc_id) +{ + drmModeConnector *connector; + drmModeEncoder *encoder = NULL; + int i, j; + + /* First, find the connector & mode */ + o->mode_valid = 0; + o->crtc = 0; + connector = drmModeGetConnector(drm_fd, o->id); + assert(connector); + + if (connector->connection != DRM_MODE_CONNECTED) { + drmModeFreeConnector(connector); + return; + } + + if (!connector->count_modes) { + fprintf(stderr, "connector %d has no modes\n", o->id); + drmModeFreeConnector(connector); + return; + } + + if (connector->connector_id != o->id) { + fprintf(stderr, "connector id doesn't match (%d != %d)\n", + connector->connector_id, o->id); + drmModeFreeConnector(connector); + return; + } + + for (j = 0; j < connector->count_modes; j++) { + o->mode = connector->modes[j]; + if (o->mode.type & DRM_MODE_TYPE_PREFERRED) { + o->mode_valid = 1; + break; + } + } + + if (!o->mode_valid) { + if (connector->count_modes > 0) { + /* use the first mode as test mode */ + o->mode = connector->modes[0]; + o->mode_valid = 1; + } + else { + fprintf(stderr, "failed to find any modes on connector %d\n", + o->id); + return; + } + } + + /* Now get the encoder */ + for (i = 0; i < connector->count_encoders; i++) { + encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]); + + if (!encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + drmModeFreeEncoder(encoder); + continue; + } + + break; + } + + o->encoder = encoder; + + if (i == resources->count_encoders) { + fprintf(stderr, "failed to find encoder\n"); + o->mode_valid = 0; + return; + } + + /* Find first CRTC not in use */ + for (i = 0; i < resources->count_crtcs; i++) { + if (resources->crtcs[i] != crtc_id) + continue; + if (resources->crtcs[i] && + (o->encoder->possible_crtcs & (1<<i))) { + o->crtc = resources->crtcs[i]; + break; + } + } + + if (!o->crtc) { + fprintf(stderr, "could not find requested crtc %d\n", crtc_id); + o->mode_valid = 0; + return; + } + + o->pipe = i; + + o->connector = connector; +} + +static void +paint_flip_mode(cairo_t *cr, int width, int height, void *priv) +{ + bool odd_frame = (bool) priv; + + if (odd_frame) + cairo_rectangle(cr, width/4, height/2, width/4, height/8); + else + cairo_rectangle(cr, width/2, height/2, width/4, height/8); + + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_fill(cr); +} + +static void set_mode(struct test_output *o, int crtc) +{ + int ret; + int bpp = 32, depth = 24; + drmEventContext evctx; + int width, height; + struct timeval end; + struct kmstest_fb fb_info[2]; + + connector_find_preferred_mode(o, crtc); + if (!o->mode_valid) + return; + + width = o->mode.hdisplay; + height = o->mode.vdisplay; + + o->fb_ids[0] = kmstest_create_fb(drm_fd, width, height, bpp, depth, + false, &fb_info[0], + paint_flip_mode, (void *)false); + o->fb_ids[1] = kmstest_create_fb(drm_fd, width, height, bpp, depth, + false, &fb_info[1], + paint_flip_mode, (void *)true); + if (!o->fb_ids[0] || !o->fb_ids[1]) { + fprintf(stderr, "failed to create fbs\n"); + exit(3); + } + + gem_close(drm_fd, fb_info[0].gem_handle); + gem_close(drm_fd, fb_info[1].gem_handle); + + kmstest_dump_mode(&o->mode); + if (drmModeSetCrtc(drm_fd, o->crtc, o->fb_ids[0], 0, 0, + &o->id, 1, &o->mode)) { + fprintf(stderr, "failed to set mode (%dx%d@%dHz): %s\n", + width, height, o->mode.vrefresh, + strerror(errno)); + exit(3); + } + + ret = drmModePageFlip(drm_fd, o->crtc, o->fb_ids[1], + DRM_MODE_PAGE_FLIP_EVENT, o); + if (ret) { + fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); + exit(4); + } + o->current_fb_id = o->fb_ids[1]; + + memset(&evctx, 0, sizeof evctx); + evctx.version = DRM_EVENT_CONTEXT_VERSION; + evctx.vblank_handler = NULL; + evctx.page_flip_handler = page_flip_handler; + + gettimeofday(&end, NULL); + end.tv_sec += 3; + + while (1) { + struct timeval now, timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(drm_fd, &fds); + ret = select(drm_fd + 1, &fds, NULL, NULL, &timeout); + + if (ret <= 0) { + fprintf(stderr, "select timed out or error (ret %d)\n", + ret); + exit(1); + } else if (FD_ISSET(0, &fds)) { + fprintf(stderr, "no fds active, breaking\n"); + exit(2); + } + + gettimeofday(&now, NULL); + if (now.tv_sec > end.tv_sec || + (now.tv_sec == end.tv_sec && now.tv_usec >= end.tv_usec)) { + ret = 0; + break; + } + + drmHandleEvent(drm_fd, &evctx); + } + + fprintf(stdout, "page flipping on crtc %d, connector %d: PASSED\n", + crtc, o->id); + + drmModeFreeEncoder(o->encoder); + drmModeFreeConnector(o->connector); +} + +static int run_test(void) +{ + struct test_output *connectors; + int c, i; + + resources = drmModeGetResources(drm_fd); + if (!resources) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + exit(5); + } + + connectors = calloc(resources->count_connectors, + sizeof(struct test_output)); + assert(connectors); + + /* Find any connected displays */ + for (c = 0; c < resources->count_connectors; c++) { + connectors[c].id = resources->connectors[c]; + for (i = 0; i < resources->count_crtcs; i++) + set_mode(&connectors[c], resources->crtcs[i]); + } + + drmModeFreeResources(resources); + return 1; +} + +int main(int argc, char **argv) +{ + drm_fd = drm_open_any(); + + run_test(); + + close(drm_fd); + + return 0; +} diff --git a/tests/gem_bad_address.c b/tests/gem_bad_address.c new file mode 100644 index 00000000..fbb96497 --- /dev/null +++ b/tests/gem_bad_address.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +#define BAD_GTT_DEST ((512*1024*1024)) /* past end of aperture */ + +static void +bad_store(void) +{ + BEGIN_BATCH(4); + OUT_BATCH(MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL | 1 << 21); + OUT_BATCH(0); + OUT_BATCH(BAD_GTT_DEST); + OUT_BATCH(0xdeadbeef); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); +} + +int main(int argc, char **argv) +{ + int fd; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + bad_store(); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_bad_batch.c b/tests/gem_bad_batch.c new file mode 100644 index 00000000..db6636ae --- /dev/null +++ b/tests/gem_bad_batch.c @@ -0,0 +1,77 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +static void +bad_batch(void) +{ + BEGIN_BATCH(2); + OUT_BATCH(MI_BATCH_BUFFER_START); + OUT_BATCH(0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); +} + +int main(int argc, char **argv) +{ + int fd; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + bad_batch(); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_bad_blit.c b/tests/gem_bad_blit.c new file mode 100644 index 00000000..22165270 --- /dev/null +++ b/tests/gem_bad_blit.c @@ -0,0 +1,121 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** @file gem_tiled_blits.c + * + * This is a test of doing many tiled blits, with a working set + * larger than the aperture size. + * + * The goal is to catch a couple types of failure; + * - Fence management problems on pre-965. + * - A17 or L-shaped memory tiling workaround problems in acceleration. + * + * The model is to fill a collection of 1MB objects in a way that can't trip + * over A6 swizzling -- upload data to a non-tiled object, blit to the tiled + * object. Then, copy the 1MB objects randomly between each other for a while. + * Finally, download their data through linear objects again and see what + * resulted. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +#define BAD_GTT_DEST ((256*1024*1024)) /* past end of aperture */ + +static void +bad_blit(drm_intel_bo *src_bo, uint32_t devid) +{ + uint32_t src_pitch = 512, dst_pitch = 512; + uint32_t cmd_bits = 0; + + if (IS_965(devid)) { + src_pitch /= 4; + cmd_bits |= XY_SRC_COPY_BLT_SRC_TILED; + } + + if (IS_965(devid)) { + dst_pitch /= 4; + cmd_bits |= XY_SRC_COPY_BLT_DST_TILED; + } + + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB | + cmd_bits); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + dst_pitch); + OUT_BATCH(0); /* dst x1,y1 */ + OUT_BATCH((64 << 16) | 64); /* 64x64 blit */ + OUT_BATCH(BAD_GTT_DEST); + OUT_BATCH(0); /* src x1,y1 */ + OUT_BATCH(src_pitch); + OUT_RELOC(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); +} + +int main(int argc, char **argv) +{ + drm_intel_bo *src; + int fd; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + src = drm_intel_bo_alloc(bufmgr, "src", 128 * 128, 4096); + + bad_blit(src, batch->devid); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_bad_length.c b/tests/gem_bad_length.c new file mode 100644 index 00000000..41f44d7f --- /dev/null +++ b/tests/gem_bad_length.c @@ -0,0 +1,132 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +#define MI_BATCH_BUFFER_END (0xA<<23) + +/* + * Testcase: Minmal bo_create and batchbuffer exec + * + * Originally this caught an kernel oops due to the unchecked assumption that + * objects have size > 0. + */ + +static uint32_t do_gem_create(int fd, int size, int *retval) +{ + struct drm_i915_gem_create create; + int ret; + + create.handle = 0; + create.size = (size + 4095) & -4096; + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); + assert(retval || ret == 0); + if (retval) + *retval = errno; + + return create.handle; +} + +static int gem_exec(int fd, struct drm_i915_gem_execbuffer2 *execbuf) +{ + return drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); +} + +static void create0(int fd) +{ + int retval = 0; + printf("trying to create a zero-length gem object\n"); + do_gem_create(fd, 0, &retval); + assert(retval == EINVAL); +} + +static void exec0(int fd) +{ + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 exec[1]; + uint32_t buf[2] = { MI_BATCH_BUFFER_END, 0 }; + + /* Just try executing with a zero-length bo. + * We expect the kernel to either accept the nop batch, or reject it + * for the zero-length buffer, but never crash. + */ + + exec[0].handle = gem_create(fd, 4096); + gem_write(fd, exec[0].handle, 0, buf, sizeof(buf)); + exec[0].relocation_count = 0; + exec[0].relocs_ptr = 0; + exec[0].alignment = 0; + exec[0].offset = 0; + exec[0].flags = 0; + exec[0].rsvd1 = 0; + exec[0].rsvd2 = 0; + + execbuf.buffers_ptr = (uintptr_t)exec; + execbuf.buffer_count = 1; + execbuf.batch_start_offset = 0; + execbuf.batch_len = sizeof(buf); + execbuf.cliprects_ptr = 0; + execbuf.num_cliprects = 0; + execbuf.DR1 = 0; + execbuf.DR4 = 0; + execbuf.flags = 0; + i915_execbuffer2_set_context_id(execbuf, 0); + execbuf.rsvd2 = 0; + + printf("trying to run an empty batchbuffer\n"); + gem_exec(fd, &execbuf); + + gem_close(fd, exec[0].handle); +} + +int main(int argc, char **argv) +{ + int fd; + + fd = drm_open_any(); + + create0(fd); + + //exec0(fd); + + close(fd); + + return 0; +} diff --git a/tests/gem_basic.c b/tests/gem_basic.c new file mode 100644 index 00000000..24ad445f --- /dev/null +++ b/tests/gem_basic.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +static void +test_bad_close(int fd) +{ + struct drm_gem_close close_bo; + int ret; + + printf("Testing error return on bad close ioctl.\n"); + + close_bo.handle = 0x10101010; + ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo); + + assert(ret == -1 && errno == EINVAL); +} + +static void +test_create_close(int fd) +{ + uint32_t handle; + + printf("Testing creating and closing an object.\n"); + + handle = gem_create(fd, 16*1024); + + gem_close(fd, handle); +} + +static void +test_create_fd_close(int fd) +{ + printf("Testing closing with an object allocated.\n"); + + gem_create(fd, 16*1024); + /* leak it */ + + close(fd); +} + +int main(int argc, char **argv) +{ + int fd; + + fd = drm_open_any(); + + test_bad_close(fd); + test_create_close(fd); + test_create_fd_close(fd); + + return 0; +} diff --git a/tests/gem_cpu_concurrent_blit.c b/tests/gem_cpu_concurrent_blit.c new file mode 100644 index 00000000..fd517d00 --- /dev/null +++ b/tests/gem_cpu_concurrent_blit.c @@ -0,0 +1,142 @@ +/* + * Copyright © 2009,2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** @file gem_cpu_concurrent_blit.c + * + * This is a test of CPU read/write behavior when writing to active + * buffers. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static void +set_bo(drm_intel_bo *bo, uint32_t val, int width, int height) +{ + int size = width * height; + uint32_t *vaddr; + + drm_intel_bo_map(bo, true); + vaddr = bo->virtual; + while (size--) + *vaddr++ = val; + drm_intel_bo_unmap(bo); +} + +static void +cmp_bo(drm_intel_bo *bo, uint32_t val, int width, int height) +{ + int size = width * height; + uint32_t *vaddr; + + drm_intel_bo_map(bo, false); + vaddr = bo->virtual; + while (size--) + assert(*vaddr++ == val); + drm_intel_bo_unmap(bo); +} + +static drm_intel_bo * +create_bo(drm_intel_bufmgr *bufmgr, uint32_t val, int width, int height) +{ + drm_intel_bo *bo; + + bo = drm_intel_bo_alloc(bufmgr, "bo", 4*width*height, 0); + assert(bo); + + set_bo(bo, val, width, height); + + return bo; +} + +int +main(int argc, char **argv) +{ + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + int num_buffers = 128, max; + drm_intel_bo *src[128], *dst[128], *dummy; + int width = 512, height = 512; + int fd; + int i; + + fd = drm_open_any(); + + max = gem_aperture_size (fd) / (1024 * 1024) / 2; + if (num_buffers > max) + num_buffers = max; + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + for (i = 0; i < num_buffers; i++) { + src[i] = create_bo(bufmgr, i, width, height); + dst[i] = create_bo(bufmgr, ~i, width, height); + } + dummy = create_bo(bufmgr, 0, width, height); + + /* try to overwrite the source values */ + for (i = 0; i < num_buffers; i++) + intel_copy_bo(batch, dst[i], src[i], width, height); + for (i = num_buffers; i--; ) + set_bo(src[i], 0xdeadbeef, width, height); + for (i = 0; i < num_buffers; i++) + cmp_bo(dst[i], i, width, height); + + /* try to read the results before the copy completes */ + for (i = 0; i < num_buffers; i++) + intel_copy_bo(batch, dst[i], src[i], width, height); + for (i = num_buffers; i--; ) + cmp_bo(dst[i], 0xdeadbeef, width, height); + + /* and finally try to trick the kernel into loosing the pending write */ + for (i = num_buffers; i--; ) + set_bo(src[i], 0xabcdabcd, width, height); + for (i = 0; i < num_buffers; i++) + intel_copy_bo(batch, dst[i], src[i], width, height); + for (i = num_buffers; i--; ) + intel_copy_bo(batch, dummy, dst[i], width, height); + for (i = num_buffers; i--; ) + cmp_bo(dst[i], 0xabcdabcd, width, height); + + return 0; +} diff --git a/tests/gem_cs_prefetch.c b/tests/gem_cs_prefetch.c new file mode 100644 index 00000000..4fb2fc4e --- /dev/null +++ b/tests/gem_cs_prefetch.c @@ -0,0 +1,169 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +/* + * Testcase: Test the CS prefetch behaviour on batches + * + * Historically the batch prefetcher doesn't check whether it's crossing page + * boundaries and likes to throw up when it gets a pagefault in return for his + * over-eager behaviour. Check for this. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +static void exec(int fd, uint32_t handle) +{ + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 gem_exec[1]; + int ret = 0; + + gem_exec[0].handle = handle; + gem_exec[0].relocation_count = 0; + gem_exec[0].relocs_ptr = 0; + gem_exec[0].alignment = 0; + gem_exec[0].offset = 0; + gem_exec[0].flags = 0; + gem_exec[0].rsvd1 = 0; + gem_exec[0].rsvd2 = 0; + + execbuf.buffers_ptr = (uintptr_t)gem_exec; + execbuf.buffer_count = 1; + execbuf.batch_start_offset = 0; + execbuf.batch_len = 4096; + execbuf.cliprects_ptr = 0; + execbuf.num_cliprects = 0; + execbuf.DR1 = 0; + execbuf.DR4 = 0; + execbuf.flags = 0; + execbuf.rsvd1 = 0; + execbuf.rsvd2 = 0; + + ret = drmIoctl(fd, + DRM_IOCTL_I915_GEM_EXECBUFFER2, + &execbuf); + gem_sync(fd, handle); + assert(ret == 0); +} + +int main(int argc, char **argv) +{ + uint32_t batch_end[4] = {MI_BATCH_BUFFER_END, 0, 0, 0}; + int fd, i, ret; + uint64_t aper_size; + int count; + drm_intel_bo *sample_batch_bo; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + if (!bufmgr) { + fprintf(stderr, "failed to init libdrm\n"); + exit(-1); + } + + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + aper_size = gem_aperture_size(fd); + + /* presume a big per-bo overhead */ + if (intel_get_total_ram_mb() < (aper_size / (1024*1024)) * 3 / 2) { + fprintf(stderr, "not enough mem to run test\n"); + return 77; + } + + count = aper_size / 4096; + + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + assert(batch); + + sample_batch_bo = drm_intel_bo_alloc(bufmgr, "", 4096, 4096); + assert(sample_batch_bo); + ret = drm_intel_bo_subdata(sample_batch_bo, 4096-sizeof(batch_end), + sizeof(batch_end), batch_end); + assert(ret == 0); + + /* fill the entire gart with batches and run them */ + for (i = 0; i < count; i++) { + drm_intel_bo *batch_bo; + + batch_bo = drm_intel_bo_alloc(bufmgr, "", 4096, 4096); + assert(batch_bo); + + /* copy the sample batch with the gpu to the new one, so that we + * also test the unmappable part of the gtt. */ + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + 4096); + OUT_BATCH(0); /* dst y1,x1 */ + OUT_BATCH((1 << 16) | 1024); + OUT_RELOC(batch_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH((0 << 16) | 0); /* src x1, y1 */ + OUT_BATCH(4096); + OUT_RELOC(sample_batch_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); + if (i % 100 == 0) + gem_sync(fd, batch_bo->handle); + + drm_intel_bo_disable_reuse(batch_bo); + + /* launch the newly created batch */ + exec(fd, batch_bo->handle); + + // leak buffers + //drm_intel_bo_unreference(batch_bo); + drmtest_progress("gem_cs_prefetch: ", i, count); + } + + fprintf(stderr, "Test suceeded, cleanup up - this might take a while.\n"); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_ctx_bad_destroy.c b/tests/gem_ctx_bad_destroy.c new file mode 100644 index 00000000..02d24eb3 --- /dev/null +++ b/tests/gem_ctx_bad_destroy.c @@ -0,0 +1,109 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +/* + * Negative test cases for destroy contexts + */ + +#include <stdio.h> +#include <string.h> +#include "i915_drm.h" +#include "drmtest.h" + +struct local_drm_i915_context_create { + __u32 ctx_id; + __u32 pad; +}; + +struct local_drm_i915_context_destroy { + __u32 ctx_id; + __u32 pad; +}; + +#define CONTEXT_CREATE_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2d, struct local_drm_i915_context_create) +#define CONTEXT_DESTROY_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2e, struct local_drm_i915_context_destroy) + +static uint32_t context_create(int fd) +{ + struct local_drm_i915_context_create create; + int ret; + + ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create); + if (ret == -1 && (errno == ENODEV || errno == EINVAL)) + exit(77); + else if (ret) + abort(); + + return create.ctx_id; +} + +static void handle_bad(int ret, int lerrno, int expected, const char *desc) +{ + if (ret != 0 && lerrno != expected) { + fprintf(stderr, "%s - errno was %d, but should have been %d\n", + desc, lerrno, expected); + exit(EXIT_FAILURE); + } else if (ret == 0) { + fprintf(stderr, "%s - Command succeeded, but should have failed\n", + desc); + exit(EXIT_FAILURE); + } +} + +int main(int argc, char *argv[]) +{ + struct local_drm_i915_context_destroy destroy; + uint32_t ctx_id; + int ret, fd; + + fd = drm_open_any(); + + ctx_id = context_create(fd); + + destroy.ctx_id = ctx_id; + /* Make sure a proper destroy works first */ + ret = drmIoctl(fd, CONTEXT_DESTROY_IOCTL, &destroy); + assert(ret == 0); + + /* try double destroy */ + ret = drmIoctl(fd, CONTEXT_DESTROY_IOCTL, &destroy); + handle_bad(ret, errno, ENOENT, "double destroy"); + + /* destroy something random */ + destroy.ctx_id = 2; + ret = drmIoctl(fd, CONTEXT_DESTROY_IOCTL, &destroy); + handle_bad(ret, errno, ENOENT, "random destroy"); + + /* Try to destroy the default context */ + destroy.ctx_id = 0; + ret = drmIoctl(fd, CONTEXT_DESTROY_IOCTL, &destroy); + handle_bad(ret, errno, ENOENT, "default destroy"); + + close(fd); + + exit(EXIT_SUCCESS); +} diff --git a/tests/gem_ctx_bad_exec.c b/tests/gem_ctx_bad_exec.c new file mode 100644 index 00000000..8a57fd41 --- /dev/null +++ b/tests/gem_ctx_bad_exec.c @@ -0,0 +1,125 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +/* + * Negative test cases: + * test we can't submit contexts to unsupported rings + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +struct local_drm_i915_gem_context_create { + __u32 ctx_id; + __u32 pad; +}; + +#define CONTEXT_CREATE_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2d, struct local_drm_i915_gem_context_create) + +static uint32_t context_create(int fd) +{ + struct local_drm_i915_gem_context_create create; + int ret; + + ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create); + if (ret == -1 && (errno == ENODEV || errno == EINVAL)) { + exit(77); + } else if (ret) { + abort(); + } + + return create.ctx_id; +} + +/* Copied from gem_exec_nop.c */ +static int exec(int fd, uint32_t handle, int ring, int ctx_id) +{ + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 gem_exec; + int ret = 0; + + gem_exec.handle = handle; + gem_exec.relocation_count = 0; + gem_exec.relocs_ptr = 0; + gem_exec.alignment = 0; + gem_exec.offset = 0; + gem_exec.flags = 0; + gem_exec.rsvd1 = 0; + gem_exec.rsvd2 = 0; + + execbuf.buffers_ptr = (uintptr_t)&gem_exec; + execbuf.buffer_count = 1; + execbuf.batch_start_offset = 0; + execbuf.batch_len = 8; + execbuf.cliprects_ptr = 0; + execbuf.num_cliprects = 0; + execbuf.DR1 = 0; + execbuf.DR4 = 0; + execbuf.flags = ring; + i915_execbuffer2_set_context_id(execbuf, ctx_id); + execbuf.rsvd2 = 0; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, + &execbuf); + gem_sync(fd, handle); + + return ret; +} + +#define MI_BATCH_BUFFER_END (0xA<<23) +int main(int argc, char *argv[]) +{ + uint32_t handle; + uint32_t batch[2] = {MI_BATCH_BUFFER_END}; + uint32_t ctx_id; + int fd; + fd = drm_open_any(); + + ctx_id = context_create(fd); + + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, sizeof(batch)); + assert(exec(fd, handle, I915_EXEC_RENDER, ctx_id) == 0); + assert(exec(fd, handle, I915_EXEC_BSD, ctx_id) != 0); + assert(exec(fd, handle, I915_EXEC_BLT, ctx_id) != 0); + + exit(EXIT_SUCCESS); +} diff --git a/tests/gem_ctx_basic.c b/tests/gem_ctx_basic.c new file mode 100644 index 00000000..632651ae --- /dev/null +++ b/tests/gem_ctx_basic.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +/* + * This test is useful for finding memory and refcount leaks. + */ + +#include <pthread.h> +#include "rendercopy.h" + +/* options */ +int num_contexts = 10; +int uncontexted = 0; /* test only context create/destroy */ +int multiple_fds = 1; +int iter = 10000; + +/* globals */ +pthread_t *threads; +int *returns; +int devid; +int fd; + +static void init_buffer(drm_intel_bufmgr *bufmgr, + struct scratch_buf *buf, + uint32_t size) +{ + buf->bo = drm_intel_bo_alloc(bufmgr, "", size, 4096); + buf->size = size; + assert(buf->bo); + buf->tiling = I915_TILING_NONE; + buf->stride = 4096; +} + +static void *work(void *arg) +{ + struct intel_batchbuffer *batch; + drm_intel_context *context; + drm_intel_bufmgr *bufmgr; + int thread_id = *(int *)arg; + int td_fd; + int i; + + if (multiple_fds) + td_fd = fd = drm_open_any(); + else + td_fd = fd; + + assert(td_fd >= 0); + + bufmgr = drm_intel_bufmgr_gem_init(td_fd, 4096); + batch = intel_batchbuffer_alloc(bufmgr, devid); + context = drm_intel_gem_context_create(bufmgr); + + if (!context) { + returns[thread_id] = 77; + goto out; + } + + for (i = 0; i < iter; i++) { + struct scratch_buf src, dst; + + init_buffer(bufmgr, &src, 4096); + init_buffer(bufmgr, &dst, 4096); + + + if (uncontexted) { + gen6_render_copyfunc(batch, &src, 0, 0, 0, 0, &dst, 0, 0); + } else { + int ret; + ret = drm_intel_bo_subdata(batch->bo, 0, 4096, batch->buffer); + assert(ret == 0); + intel_batchbuffer_flush_with_context(batch, context); + } + } + +out: + drm_intel_gem_context_destroy(context); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + if (multiple_fds) + close(td_fd); + + pthread_exit(&returns[thread_id]); +} + +static void parse(int argc, char *argv[]) +{ + int opt; + while ((opt = getopt(argc, argv, "i:c:n:muh?")) != -1) { + switch (opt) { + case 'i': + iter = atoi(optarg); + break; + case 'c': + num_contexts = atoi(optarg); + break; + case 'm': + multiple_fds = 1; + break; + case 'u': + uncontexted = 1; + break; + case 'h': + case '?': + default: + exit(EXIT_SUCCESS); + break; + } + } +} + +int main(int argc, char *argv[]) +{ + int i; + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + + parse(argc, argv); + + threads = calloc(num_contexts, sizeof(*threads)); + returns = calloc(num_contexts, sizeof(*returns)); + + for (i = 0; i < num_contexts; i++) + pthread_create(&threads[i], NULL, work, &i); + + for (i = 0; i < num_contexts; i++) { + int thread_status, ret; + void *retval; + ret = pthread_join(threads[i], &retval); + thread_status = *(int *)retval; + if (!ret && thread_status) + exit(thread_status); + } + + free(returns); + free(threads); + close(fd); + + exit(EXIT_SUCCESS); +} diff --git a/tests/gem_ctx_create.c b/tests/gem_ctx_create.c new file mode 100644 index 00000000..def76d34 --- /dev/null +++ b/tests/gem_ctx_create.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#include <stdio.h> +#include <string.h> +#include "i915_drm.h" +#include "drmtest.h" + +struct local_drm_i915_gem_context_create { + __u32 ctx_id; + __u32 pad; +}; + +#define CONTEXT_CREATE_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2d, struct local_drm_i915_gem_context_create) + +int main(int argc, char *argv[]) +{ + int ret, fd; + struct local_drm_i915_gem_context_create create; + + create.ctx_id = rand(); + create.pad = rand(); + + fd = drm_open_any(); + + ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create); + if (ret != 0 && (errno == ENODEV || errno == EINVAL)) { + fprintf(stderr, "Kernel is too old, or contexts not supported: %s\n", + strerror(errno)); + exit(77); + } else if (ret != 0) { + fprintf(stderr, "%s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + assert(create.ctx_id != 0); + + close(fd); + + exit(EXIT_SUCCESS); +} diff --git a/tests/gem_ctx_exec.c b/tests/gem_ctx_exec.c new file mode 100644 index 00000000..423f1eec --- /dev/null +++ b/tests/gem_ctx_exec.c @@ -0,0 +1,139 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +/* + * This test covers basic context switch functionality + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +struct local_drm_i915_gem_context_create { + __u32 ctx_id; + __u32 pad; +}; + +struct local_drm_i915_gem_context_destroy { + __u32 ctx_id; + __u32 pad; +}; + +#define CONTEXT_CREATE_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2d, struct local_drm_i915_gem_context_create) +#define CONTEXT_DESTROY_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x23, struct local_drm_i915_gem_context_destroy) + +static uint32_t context_create(int fd) +{ + struct local_drm_i915_gem_context_create create; + int ret; + + ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create); + if (ret == -1 && (errno == ENODEV || errno == EINVAL)) + exit(77); + else if (ret) + abort(); + + return create.ctx_id; +} + +static void context_destroy(int fd, uint32_t ctx_id) +{ + struct local_drm_i915_gem_context_destroy destroy; + destroy.ctx_id = ctx_id; + do_ioctl(fd, CONTEXT_DESTROY_IOCTL, &destroy); +} + +/* Copied from gem_exec_nop.c */ +static int exec(int fd, uint32_t handle, int ring, int ctx_id) +{ + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 gem_exec; + int ret = 0; + + gem_exec.handle = handle; + gem_exec.relocation_count = 0; + gem_exec.relocs_ptr = 0; + gem_exec.alignment = 0; + gem_exec.offset = 0; + gem_exec.flags = 0; + gem_exec.rsvd1 = 0; + gem_exec.rsvd2 = 0; + + execbuf.buffers_ptr = (uintptr_t)&gem_exec; + execbuf.buffer_count = 1; + execbuf.batch_start_offset = 0; + execbuf.batch_len = 8; + execbuf.cliprects_ptr = 0; + execbuf.num_cliprects = 0; + execbuf.DR1 = 0; + execbuf.DR4 = 0; + execbuf.flags = ring; + i915_execbuffer2_set_context_id(execbuf, ctx_id); + execbuf.rsvd2 = 0; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, + &execbuf); + gem_sync(fd, handle); + + return ret; +} + +#define MI_BATCH_BUFFER_END (0xA<<23) +int main(int argc, char *argv[]) +{ + uint32_t handle; + uint32_t batch[2] = {0, MI_BATCH_BUFFER_END}; + uint32_t ctx_id; + int fd; + fd = drm_open_any(); + + ctx_id = context_create(fd); + handle = gem_create(fd, 4096); + + gem_write(fd, handle, 0, batch, sizeof(batch)); + assert(exec(fd, handle, I915_EXEC_RENDER, ctx_id) == 0); + context_destroy(fd, ctx_id); + + ctx_id = context_create(fd); + assert(exec(fd, handle, I915_EXEC_RENDER, ctx_id) == 0); + context_destroy(fd, ctx_id); + + exit(EXIT_SUCCESS); +} diff --git a/tests/gem_double_irq_loop.c b/tests/gem_double_irq_loop.c new file mode 100644 index 00000000..f2f8b1a8 --- /dev/null +++ b/tests/gem_double_irq_loop.c @@ -0,0 +1,147 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> (based on gem_storedw_*.c) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" +#include "i830_reg.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static drm_intel_bo *target_buffer, *blt_bo; + +/* + * Testcase: Basic check for missed irqs on blt + * + * Execs one large and then immediately a tiny batch on the blt ring. Then waits + * on the second batch. This hopefully catches races in our irq acknowledgement. + */ + + +#define MI_COND_BATCH_BUFFER_END (0x36<<23 | 1) +#define MI_DO_COMPARE (1<<21) +static void +dummy_reloc_loop(void) +{ + int i; + + for (i = 0; i < 0x800; i++) { + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + 4*4096); + OUT_BATCH(2048 << 16 | 0); + OUT_BATCH((4096) << 16 | (2048)); + OUT_RELOC_FENCED(blt_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(4*4096); + OUT_RELOC_FENCED(blt_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + intel_batchbuffer_flush(batch); + + BEGIN_BATCH(4); + OUT_BATCH(MI_FLUSH_DW | 1); + OUT_BATCH(0); /* reserved */ + OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(MI_NOOP | (1<<22) | (0xf)); + ADVANCE_BATCH(); + intel_batchbuffer_flush(batch); + + drm_intel_bo_map(target_buffer, 0); + // map to force completion + drm_intel_bo_unmap(target_buffer); + } +} + +int main(int argc, char **argv) +{ + int fd; + int devid; + + if (argc != 1) { + fprintf(stderr, "usage: %s\n", argv[0]); + exit(-1); + } + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + if (!HAS_BLT_RING(devid)) { + fprintf(stderr, "not (yet) implemented for pre-snb\n"); + return 77; + } + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + if (!bufmgr) { + fprintf(stderr, "failed to init libdrm\n"); + exit(-1); + } + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, devid); + if (!batch) { + fprintf(stderr, "failed to create batch buffer\n"); + exit(-1); + } + + target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096); + if (!target_buffer) { + fprintf(stderr, "failed to alloc target buffer\n"); + exit(-1); + } + + blt_bo = drm_intel_bo_alloc(bufmgr, "target bo", 4*4096*4096, 4096); + if (!blt_bo) { + fprintf(stderr, "failed to alloc blt buffer\n"); + exit(-1); + } + + dummy_reloc_loop(); + + drm_intel_bo_unreference(target_buffer); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_dummy_reloc_loop.c b/tests/gem_dummy_reloc_loop.c new file mode 100644 index 00000000..82d8f77e --- /dev/null +++ b/tests/gem_dummy_reloc_loop.c @@ -0,0 +1,194 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> (based on gem_storedw_*.c) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" +#include "i830_reg.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static drm_intel_bo *target_buffer; + +/* + * Testcase: Basic check of ring<->cpu sync using a dummy reloc + * + * The last test (that randomly switches the ring) seems to be pretty effective + * at hitting the missed irq bug that's worked around with the HWSTAM irq write. + */ + + +#define MI_COND_BATCH_BUFFER_END (0x36<<23 | 1) +#define MI_DO_COMPARE (1<<21) +static void +dummy_reloc_loop(int ring) +{ + int i; + + for (i = 0; i < 0x100000; i++) { + if (ring == I915_EXEC_RENDER) { + BEGIN_BATCH(4); + OUT_BATCH(MI_COND_BATCH_BUFFER_END | MI_DO_COMPARE); + OUT_BATCH(0xffffffff); /* compare dword */ + OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(MI_NOOP); + ADVANCE_BATCH(); + } else { + BEGIN_BATCH(4); + OUT_BATCH(MI_FLUSH_DW | 1); + OUT_BATCH(0); /* reserved */ + OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(MI_NOOP | (1<<22) | (0xf)); + ADVANCE_BATCH(); + } + intel_batchbuffer_flush_on_ring(batch, ring); + + drm_intel_bo_map(target_buffer, 0); + // map to force completion + drm_intel_bo_unmap(target_buffer); + } +} + +static void +dummy_reloc_loop_random_ring(void) +{ + int i; + + srandom(0xdeadbeef); + + for (i = 0; i < 0x100000; i++) { + int ring = random() % 3 + 1; + + if (ring == I915_EXEC_RENDER) { + BEGIN_BATCH(4); + OUT_BATCH(MI_COND_BATCH_BUFFER_END | MI_DO_COMPARE); + OUT_BATCH(0xffffffff); /* compare dword */ + OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(MI_NOOP); + ADVANCE_BATCH(); + } else { + BEGIN_BATCH(4); + OUT_BATCH(MI_FLUSH_DW | 1); + OUT_BATCH(0); /* reserved */ + OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(MI_NOOP | (1<<22) | (0xf)); + ADVANCE_BATCH(); + } + intel_batchbuffer_flush_on_ring(batch, ring); + + drm_intel_bo_map(target_buffer, 0); + // map to force waiting on rendering + drm_intel_bo_unmap(target_buffer); + } +} + +int main(int argc, char **argv) +{ + int fd; + int devid; + + if (argc != 1) { + fprintf(stderr, "usage: %s\n", argv[0]); + exit(-1); + } + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + if (!HAS_BLT_RING(devid)) { + fprintf(stderr, "not (yet) implemented for pre-snb\n"); + return 77; + } + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + if (!bufmgr) { + fprintf(stderr, "failed to init libdrm\n"); + exit(-1); + } + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, devid); + if (!batch) { + fprintf(stderr, "failed to create batch buffer\n"); + exit(-1); + } + + target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096); + if (!target_buffer) { + fprintf(stderr, "failed to alloc target buffer\n"); + exit(-1); + } + + fprintf(stderr, "running dummy loop on render\n"); + dummy_reloc_loop(I915_EXEC_RENDER); + fprintf(stderr, "dummy loop run on render completed\n"); + + if (!HAS_BSD_RING(devid)) + goto skip; + + sleep(2); + fprintf(stderr, "running dummy loop on bsd\n"); + dummy_reloc_loop(I915_EXEC_BSD); + fprintf(stderr, "dummy loop run on bsd completed\n"); + + if (!HAS_BLT_RING(devid)) + goto skip; + + sleep(2); + fprintf(stderr, "running dummy loop on blt\n"); + dummy_reloc_loop(I915_EXEC_BLT); + fprintf(stderr, "dummy loop run on blt completed\n"); + + sleep(2); + fprintf(stderr, "running dummy loop on random rings\n"); + dummy_reloc_loop_random_ring(); + fprintf(stderr, "dummy loop run on random rings completed\n"); + +skip: + drm_intel_bo_unreference(target_buffer); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_exec_bad_domains.c b/tests/gem_exec_bad_domains.c new file mode 100644 index 00000000..f3ee08b7 --- /dev/null +++ b/tests/gem_exec_bad_domains.c @@ -0,0 +1,145 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +/* Testcase: Test whether the kernel rejects relocations with non-gpu domains + * + * If it does not, it'll oops somewhen later on because we don't expect that. + */ + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +#define BAD_GTT_DEST ((512*1024*1024)) /* past end of aperture */ + +static int +run_batch(void) +{ + unsigned int used = batch->ptr - batch->buffer; + int ret; + + if (used == 0) + return 0; + + /* Round batchbuffer usage to 2 DWORDs. */ + if ((used & 4) == 0) { + *(uint32_t *) (batch->ptr) = 0; /* noop */ + batch->ptr += 4; + } + + /* Mark the end of the buffer. */ + *(uint32_t *)(batch->ptr) = MI_BATCH_BUFFER_END; /* noop */ + batch->ptr += 4; + used = batch->ptr - batch->buffer; + + ret = drm_intel_bo_subdata(batch->bo, 0, used, batch->buffer); + assert(ret == 0); + + batch->ptr = NULL; + + ret = drm_intel_bo_mrb_exec(batch->bo, used, NULL, 0, 0, 0); + + intel_batchbuffer_reset(batch); + + return ret; +} + +int main(int argc, char **argv) +{ + int fd, ret; + drm_intel_bo *tmp; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + tmp = drm_intel_bo_alloc(bufmgr, "tmp", 128 * 128, 4096); + + BEGIN_BATCH(2); + OUT_BATCH(0); + OUT_RELOC(tmp, I915_GEM_DOMAIN_CPU, 0, 0); + ADVANCE_BATCH(); + ret = run_batch(); + if (ret != -EINVAL) { + fprintf(stderr, "(cpu, 0) reloc not rejected\n"); + exit(1); + } + + BEGIN_BATCH(2); + OUT_BATCH(0); + OUT_RELOC(tmp, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU, 0); + ADVANCE_BATCH(); + ret = run_batch(); + if (ret != -EINVAL) { + fprintf(stderr, "(cpu, cpu) reloc not rejected\n"); + exit(1); + } + + BEGIN_BATCH(2); + OUT_BATCH(0); + OUT_RELOC(tmp, I915_GEM_DOMAIN_GTT, 0, 0); + ADVANCE_BATCH(); + ret = run_batch(); + if (ret != -EINVAL) { + fprintf(stderr, "(gtt, 0) reloc not rejected\n"); + exit(1); + } + + BEGIN_BATCH(2); + OUT_BATCH(0); + OUT_RELOC(tmp, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT, 0); + ADVANCE_BATCH(); + ret = run_batch(); + if (ret != -EINVAL) { + fprintf(stderr, "(gtt, gtt) reloc not rejected\n"); + exit(1); + } + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_exec_blt.c b/tests/gem_exec_blt.c new file mode 100644 index 00000000..eb5ae668 --- /dev/null +++ b/tests/gem_exec_blt.c @@ -0,0 +1,263 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_chipset.h" +#include "intel_gpu_tools.h" + +#define OBJECT_SIZE 16384 + +#define COPY_BLT_CMD (2<<29|0x53<<22|0x6) +#define BLT_WRITE_ALPHA (1<<21) +#define BLT_WRITE_RGB (1<<20) +#define BLT_SRC_TILED (1<<15) +#define BLT_DST_TILED (1<<11) + +static int gem_linear_blt(uint32_t *batch, + uint32_t src, + uint32_t dst, + uint32_t length, + struct drm_i915_gem_relocation_entry *reloc) +{ + uint32_t *b = batch; + int height = length / (16 * 1024); + + assert(height <= 1<<16); + + if (height) { + b[0] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB; + b[1] = 0xcc << 16 | 1 << 25 | 1 << 24 | (16*1024); + b[2] = 0; + b[3] = height << 16 | (4*1024); + b[4] = 0; + reloc->offset = (b-batch+4) * sizeof(uint32_t); + reloc->delta = 0; + reloc->target_handle = dst; + reloc->read_domains = I915_GEM_DOMAIN_RENDER; + reloc->write_domain = I915_GEM_DOMAIN_RENDER; + reloc->presumed_offset = 0; + reloc++; + + b[5] = 0; + b[6] = 16*1024; + b[7] = 0; + reloc->offset = (b-batch+7) * sizeof(uint32_t); + reloc->delta = 0; + reloc->target_handle = src; + reloc->read_domains = I915_GEM_DOMAIN_RENDER; + reloc->write_domain = 0; + reloc->presumed_offset = 0; + reloc++; + + b += 8; + length -= height * 16*1024; + } + + if (length) { + b[0] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB; + b[1] = 0xcc << 16 | 1 << 25 | 1 << 24 | (16*1024); + b[2] = height << 16; + b[3] = (1+height) << 16 | (length / 4); + b[4] = 0; + reloc->offset = (b-batch+4) * sizeof(uint32_t); + reloc->delta = 0; + reloc->target_handle = dst; + reloc->read_domains = I915_GEM_DOMAIN_RENDER; + reloc->write_domain = I915_GEM_DOMAIN_RENDER; + reloc->presumed_offset = 0; + reloc++; + + b[5] = height << 16; + b[6] = 16*1024; + b[7] = 0; + reloc->offset = (b-batch+7) * sizeof(uint32_t); + reloc->delta = 0; + reloc->target_handle = src; + reloc->read_domains = I915_GEM_DOMAIN_RENDER; + reloc->write_domain = 0; + reloc->presumed_offset = 0; + reloc++; + + b += 8; + } + + b[0] = MI_BATCH_BUFFER_END; + b[1] = 0; + + return (b+2 - batch) * sizeof(uint32_t); +} + +static int gem_exec(int fd, struct drm_i915_gem_execbuffer2 *execbuf, int loops) +{ + int ret = 0; + + while (loops-- && ret == 0) { + ret = drmIoctl(fd, + DRM_IOCTL_I915_GEM_EXECBUFFER2, + execbuf); + } + + return ret; +} + +static double elapsed(const struct timeval *start, + const struct timeval *end, + int loop) +{ + return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop; +} + +static const char *bytes_per_sec(char *buf, double v) +{ + const char *order[] = { + "", + "KiB", + "MiB", + "GiB", + "TiB", + "PiB", + NULL, + }, **o = order; + + while (v > 1024 && o[1]) { + v /= 1024; + o++; + } + sprintf(buf, "%.1f%s/s", v, *o); + return buf; +} + +static void run(int object_size) +{ + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 exec[3]; + struct drm_i915_gem_relocation_entry reloc[4]; + uint32_t buf[20]; + uint32_t handle, src, dst; + int fd, len, count; + int ring; + + fd = drm_open_any(); + handle = gem_create(fd, 4096); + src = gem_create(fd, object_size); + dst = gem_create(fd, object_size); + + len = gem_linear_blt(buf, src, dst, object_size, reloc); + gem_write(fd, handle, 0, buf, len); + + exec[0].handle = src; + exec[0].relocation_count = 0; + exec[0].relocs_ptr = 0; + exec[0].alignment = 0; + exec[0].offset = 0; + exec[0].flags = 0; + exec[0].rsvd1 = 0; + exec[0].rsvd2 = 0; + + exec[1].handle = dst; + exec[1].relocation_count = 0; + exec[1].relocs_ptr = 0; + exec[1].alignment = 0; + exec[1].offset = 0; + exec[1].flags = 0; + exec[1].rsvd1 = 0; + exec[1].rsvd2 = 0; + + exec[2].handle = handle; + exec[2].relocation_count = len > 40 ? 4 : 2; + exec[2].relocs_ptr = (uintptr_t)reloc; + exec[2].alignment = 0; + exec[2].offset = 0; + exec[2].flags = 0; + exec[2].rsvd1 = 0; + exec[2].rsvd2 = 0; + + ring = 0; + if (HAS_BLT_RING(intel_get_drm_devid(fd))) + ring = I915_EXEC_BLT; + + execbuf.buffers_ptr = (uintptr_t)exec; + execbuf.buffer_count = 3; + execbuf.batch_start_offset = 0; + execbuf.batch_len = len; + execbuf.cliprects_ptr = 0; + execbuf.num_cliprects = 0; + execbuf.DR1 = 0; + execbuf.DR4 = 0; + execbuf.flags = ring; + i915_execbuffer2_set_context_id(execbuf, 0); + execbuf.rsvd2 = 0; + + for (count = 1; count <= 1<<17; count <<= 1) { + struct timeval start, end; + + gettimeofday(&start, NULL); + if (gem_exec(fd, &execbuf, count)) + exit(1); + gem_sync(fd, handle); + gettimeofday(&end, NULL); + printf("Time to blt %d bytes x %6d: %7.3fµs, %s\n", + object_size, count, + elapsed(&start, &end, count), + bytes_per_sec((char *)buf, object_size/elapsed(&start, &end, count)*1e6)); + fflush(stdout); + } + gem_close(fd, handle); + + close(fd); +} + +int main(int argc, char **argv) +{ + int i; + + if (argc > 1) { + for (i = 1; i < argc; i++) { + int object_size = atoi(argv[i]); + if (object_size) + run((object_size + 3) & -4); + } + } else + run(OBJECT_SIZE); + + return 0; +} diff --git a/tests/gem_exec_faulting_reloc.c b/tests/gem_exec_faulting_reloc.c new file mode 100644 index 00000000..863a1b03 --- /dev/null +++ b/tests/gem_exec_faulting_reloc.c @@ -0,0 +1,226 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_chipset.h" +#include "intel_gpu_tools.h" + +/* Testcase: Submit patches with relocations in memory that will fault + * + * To be really evil, use a gtt mmap for them. + */ + +#define OBJECT_SIZE 16384 + +#define COPY_BLT_CMD (2<<29|0x53<<22|0x6) +#define BLT_WRITE_ALPHA (1<<21) +#define BLT_WRITE_RGB (1<<20) +#define BLT_SRC_TILED (1<<15) +#define BLT_DST_TILED (1<<11) + +static int gem_linear_blt(uint32_t *batch, + uint32_t src, + uint32_t dst, + uint32_t length, + struct drm_i915_gem_relocation_entry *reloc) +{ + uint32_t *b = batch; + int height = length / (16 * 1024); + + assert(height <= 1<<16); + + if (height) { + b[0] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB; + b[1] = 0xcc << 16 | 1 << 25 | 1 << 24 | (16*1024); + b[2] = 0; + b[3] = height << 16 | (4*1024); + b[4] = 0; + reloc->offset = (b-batch+4) * sizeof(uint32_t); + reloc->delta = 0; + reloc->target_handle = dst; + reloc->read_domains = I915_GEM_DOMAIN_RENDER; + reloc->write_domain = I915_GEM_DOMAIN_RENDER; + reloc->presumed_offset = 0; + reloc++; + + b[5] = 0; + b[6] = 16*1024; + b[7] = 0; + reloc->offset = (b-batch+7) * sizeof(uint32_t); + reloc->delta = 0; + reloc->target_handle = src; + reloc->read_domains = I915_GEM_DOMAIN_RENDER; + reloc->write_domain = 0; + reloc->presumed_offset = 0; + reloc++; + + b += 8; + length -= height * 16*1024; + } + + if (length) { + b[0] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB; + b[1] = 0xcc << 16 | 1 << 25 | 1 << 24 | (16*1024); + b[2] = height << 16; + b[3] = (1+height) << 16 | (length / 4); + b[4] = 0; + reloc->offset = (b-batch+4) * sizeof(uint32_t); + reloc->delta = 0; + reloc->target_handle = dst; + reloc->read_domains = I915_GEM_DOMAIN_RENDER; + reloc->write_domain = I915_GEM_DOMAIN_RENDER; + reloc->presumed_offset = 0; + reloc++; + + b[5] = height << 16; + b[6] = 16*1024; + b[7] = 0; + reloc->offset = (b-batch+7) * sizeof(uint32_t); + reloc->delta = 0; + reloc->target_handle = src; + reloc->read_domains = I915_GEM_DOMAIN_RENDER; + reloc->write_domain = 0; + reloc->presumed_offset = 0; + reloc++; + + b += 8; + } + + b[0] = MI_BATCH_BUFFER_END; + b[1] = 0; + + return (b+2 - batch) * sizeof(uint32_t); +} + +static void gem_exec(int fd, struct drm_i915_gem_execbuffer2 *execbuf) +{ + int ret; + + ret = drmIoctl(fd, + DRM_IOCTL_I915_GEM_EXECBUFFER2, + execbuf); + assert(ret == 0); +} + +static void run(int object_size) +{ + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 exec[3]; + struct drm_i915_gem_relocation_entry reloc[4]; + uint32_t buf[20]; + uint32_t handle, handle_relocs, src, dst; + void *gtt_relocs; + int fd, len; + int ring; + + fd = drm_open_any(); + handle = gem_create(fd, 4096); + src = gem_create(fd, object_size); + dst = gem_create(fd, object_size); + + len = gem_linear_blt(buf, src, dst, object_size, reloc); + gem_write(fd, handle, 0, buf, len); + + exec[0].handle = src; + exec[0].relocation_count = 0; + exec[0].relocs_ptr = 0; + exec[0].alignment = 0; + exec[0].offset = 0; + exec[0].flags = 0; + exec[0].rsvd1 = 0; + exec[0].rsvd2 = 0; + + exec[1].handle = dst; + exec[1].relocation_count = 0; + exec[1].relocs_ptr = 0; + exec[1].alignment = 0; + exec[1].offset = 0; + exec[1].flags = 0; + exec[1].rsvd1 = 0; + exec[1].rsvd2 = 0; + + handle_relocs = gem_create(fd, 4096); + gem_write(fd, handle_relocs, 0, reloc, sizeof(reloc)); + gtt_relocs = gem_mmap(fd, handle_relocs, 4096, + PROT_READ | PROT_WRITE); + assert(gtt_relocs); + + exec[2].handle = handle; + exec[2].relocation_count = len > 40 ? 4 : 2; + /* A newly mmap gtt bo will fault on first access. */ + exec[2].relocs_ptr = (uintptr_t)gtt_relocs; + exec[2].alignment = 0; + exec[2].offset = 0; + exec[2].flags = 0; + exec[2].rsvd1 = 0; + exec[2].rsvd2 = 0; + + ring = 0; + if (HAS_BLT_RING(intel_get_drm_devid(fd))) + ring = I915_EXEC_BLT; + + execbuf.buffers_ptr = (uintptr_t)exec; + execbuf.buffer_count = 3; + execbuf.batch_start_offset = 0; + execbuf.batch_len = len; + execbuf.cliprects_ptr = 0; + execbuf.num_cliprects = 0; + execbuf.DR1 = 0; + execbuf.DR4 = 0; + execbuf.flags = ring; + i915_execbuffer2_set_context_id(execbuf, 0); + execbuf.rsvd2 = 0; + + gem_exec(fd, &execbuf); + gem_sync(fd, handle); + + gem_close(fd, handle); + + close(fd); +} + +int main(int argc, char **argv) +{ + run(OBJECT_SIZE); + + return 0; +} diff --git a/tests/gem_exec_nop.c b/tests/gem_exec_nop.c new file mode 100644 index 00000000..9dd055cf --- /dev/null +++ b/tests/gem_exec_nop.c @@ -0,0 +1,119 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +#define MI_BATCH_BUFFER_END (0xA<<23) + +static double elapsed(const struct timeval *start, + const struct timeval *end, + int loop) +{ + return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop; +} + +static int exec(int fd, uint32_t handle, int loops) +{ + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 gem_exec[1]; + int ret = 0; + + gem_exec[0].handle = handle; + gem_exec[0].relocation_count = 0; + gem_exec[0].relocs_ptr = 0; + gem_exec[0].alignment = 0; + gem_exec[0].offset = 0; + gem_exec[0].flags = 0; + gem_exec[0].rsvd1 = 0; + gem_exec[0].rsvd2 = 0; + + execbuf.buffers_ptr = (uintptr_t)gem_exec; + execbuf.buffer_count = 1; + execbuf.batch_start_offset = 0; + execbuf.batch_len = 8; + execbuf.cliprects_ptr = 0; + execbuf.num_cliprects = 0; + execbuf.DR1 = 0; + execbuf.DR4 = 0; + execbuf.flags = 0; + i915_execbuffer2_set_context_id(execbuf, 0); + execbuf.rsvd2 = 0; + + while (loops-- && ret == 0) { + ret = drmIoctl(fd, + DRM_IOCTL_I915_GEM_EXECBUFFER2, + &execbuf); + } + gem_sync(fd, handle); + + return ret; +} + +int main(int argc, char **argv) +{ + uint32_t batch[2] = {MI_BATCH_BUFFER_END}; + uint32_t handle; + int count; + int fd; + + fd = drm_open_any(); + + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, sizeof(batch)); + + for (count = 1; count <= 1<<17; count <<= 1) { + struct timeval start, end; + + gettimeofday(&start, NULL); + if (exec(fd, handle, count)) + exit(1); + gettimeofday(&end, NULL); + printf("Time to exec x %d: %7.3fµs\n", + count, elapsed(&start, &end, count)); + fflush(stdout); + } + gem_close(fd, handle); + + close(fd); + + return 0; +} diff --git a/tests/gem_fence_thrash.c b/tests/gem_fence_thrash.c new file mode 100644 index 00000000..3d50e334 --- /dev/null +++ b/tests/gem_fence_thrash.c @@ -0,0 +1,119 @@ +/* + * Copyright © 2008-9 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include "config.h" + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <pthread.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +#define OBJECT_SIZE (128*1024) /* restricted to 1MiB alignment on i915 fences */ + +/* Before introduction of the LRU list for fences, allocation of a fence for a page + * fault would use the first inactive fence (i.e. in preference one with no outstanding + * GPU activity, or it would wait on the first to finish). Given the choice, it would simply + * reuse the fence that had just been allocated for the previous page-fault - the worst choice + * when copying between two buffers and thus constantly swapping fences. + */ + +static void * +bo_create (int fd) +{ + void *ptr; + int handle; + + handle = gem_create(fd, OBJECT_SIZE); + + gem_set_tiling(fd, handle, I915_TILING_X, 1024); + + ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE); + + /* XXX: mmap_gtt pulls the bo into the GTT read domain. */ + gem_sync(fd, handle); + + return ptr; +} + +static void * +bo_copy (void *_arg) +{ + int fd = *(int *)_arg; + int n; + char *a, *b; + + a = bo_create (fd); + b = bo_create (fd); + + for (n = 0; n < 1000; n++) { + memcpy (a, b, OBJECT_SIZE); + sched_yield (); + } + + return NULL; +} + +int +main(int argc, char **argv) +{ + drm_i915_getparam_t gp; + pthread_t threads[32]; + int n, num_fences; + int fd, ret; + + fd = drm_open_any(); + + gp.param = I915_PARAM_NUM_FENCES_AVAIL; + gp.value = &num_fences; + ret = ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp); + assert (ret == 0); + + printf ("creating %d threads\n", num_fences); + assert (num_fences < sizeof (threads) / sizeof (threads[0])); + + for (n = 0; n < num_fences; n++) + pthread_create (&threads[n], NULL, bo_copy, &fd); + + for (n = 0; n < num_fences; n++) + pthread_join (threads[n], NULL); + + close(fd); + + return 0; +} diff --git a/tests/gem_fenced_exec_thrash.c b/tests/gem_fenced_exec_thrash.c new file mode 100644 index 00000000..8281449e --- /dev/null +++ b/tests/gem_fenced_exec_thrash.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <drm.h> +#include <i915_drm.h> + +#include "drmtest.h" + +#define WIDTH 1024 +#define HEIGHT 1024 +#define OBJECT_SIZE (4*WIDTH*HEIGHT) + +#define BATCH_SIZE 4096 + +#define MAX_FENCES 16 + +#define MI_BATCH_BUFFER_END (0xA<<23) + +/* + * Testcase: execbuf fence accounting + * + * We had a bug where we were falsely accounting upon reservation already + * fenced buffers as occupying a fence register even if they did not require + * one for the batch. + * + * We aim to exercise this by performing a sequence of fenced BLT + * with 2*num_avail_fence buffers, but alternating which half are fenced in + * each command. + */ + +static uint32_t +tiled_bo_create (int fd) +{ + uint32_t handle; + + handle = gem_create(fd, OBJECT_SIZE); + + gem_set_tiling(fd, handle, I915_TILING_X, WIDTH*4); + + return handle; +} + +static uint32_t +batch_create (int fd) +{ + uint32_t buf[] = { MI_BATCH_BUFFER_END, 0 }; + uint32_t batch_handle; + + batch_handle = gem_create(fd, BATCH_SIZE); + + gem_write(fd, batch_handle, 0, buf, sizeof(buf)); + + return batch_handle; +} + +static int get_num_fences(int fd) +{ + drm_i915_getparam_t gp; + int ret, val; + + gp.param = I915_PARAM_NUM_FENCES_AVAIL; + gp.value = &val; + ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp); + assert (ret == 0); + + printf ("total %d fences\n", val); + assert(val > 4); + + return val - 2; +} + +static void fill_reloc(struct drm_i915_gem_relocation_entry *reloc, uint32_t handle) +{ + reloc->offset = 2 * sizeof(uint32_t); + reloc->target_handle = handle; + reloc->read_domains = I915_GEM_DOMAIN_RENDER; + reloc->write_domain = 0; +} + +int +main(int argc, char **argv) +{ + struct drm_i915_gem_execbuffer2 execbuf[2]; + struct drm_i915_gem_exec_object2 exec[2][2*MAX_FENCES+1]; + struct drm_i915_gem_relocation_entry reloc[2*MAX_FENCES]; + + int fd = drm_open_any(); + int i, n, num_fences; + int loop = 1000; + + memset(execbuf, 0, sizeof(execbuf)); + memset(exec, 0, sizeof(exec)); + memset(reloc, 0, sizeof(reloc)); + + num_fences = get_num_fences(fd) & ~1; + assert(num_fences <= MAX_FENCES); + for (n = 0; n < 2*num_fences; n++) { + uint32_t handle = tiled_bo_create(fd); + exec[1][2*num_fences - n-1].handle = exec[0][n].handle = handle; + fill_reloc(&reloc[n], handle); + } + + for (i = 0; i < 2; i++) { + for (n = 0; n < num_fences; n++) + exec[i][n].flags = EXEC_OBJECT_NEEDS_FENCE; + + exec[i][2*num_fences].handle = batch_create(fd); + exec[i][2*num_fences].relocs_ptr = (uintptr_t)reloc; + exec[i][2*num_fences].relocation_count = 2*num_fences; + + execbuf[i].buffers_ptr = (uintptr_t)exec[i]; + execbuf[i].buffer_count = 2*num_fences+1; + execbuf[i].batch_len = 2*sizeof(uint32_t); + } + + do { + int ret; + + ret = drmIoctl(fd, + DRM_IOCTL_I915_GEM_EXECBUFFER2, + &execbuf[0]); + assert(ret == 0); + + ret = drmIoctl(fd, + DRM_IOCTL_I915_GEM_EXECBUFFER2, + &execbuf[1]); + assert(ret == 0); + } while (--loop); + + close(fd); + + return 0; +} diff --git a/tests/gem_flink.c b/tests/gem_flink.c new file mode 100644 index 00000000..c8694808 --- /dev/null +++ b/tests/gem_flink.c @@ -0,0 +1,130 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +static void +test_flink(int fd) +{ + struct drm_i915_gem_create create; + struct drm_gem_flink flink; + struct drm_gem_open gem_open; + int ret; + + printf("Testing flink and open.\n"); + + memset(&create, 0, sizeof(create)); + create.size = 16 * 1024; + ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); + assert(ret == 0); + + flink.handle = create.handle; + ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink); + assert(ret == 0); + + gem_open.name = flink.name; + ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &gem_open); + assert(ret == 0); + assert(gem_open.handle != 0); +} + +static void +test_double_flink(int fd) +{ + struct drm_i915_gem_create create; + struct drm_gem_flink flink; + struct drm_gem_flink flink2; + int ret; + + printf("Testing repeated flink.\n"); + + memset(&create, 0, sizeof(create)); + create.size = 16 * 1024; + ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); + assert(ret == 0); + + flink.handle = create.handle; + ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink); + assert(ret == 0); + + flink2.handle = create.handle; + ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink2); + assert(ret == 0); + assert(flink2.name == flink.name); +} + +static void +test_bad_flink(int fd) +{ + struct drm_gem_flink flink; + int ret; + + printf("Testing error return on bad flink ioctl.\n"); + + flink.handle = 0x10101010; + ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink); + assert(ret == -1 && errno == ENOENT); +} + +static void +test_bad_open(int fd) +{ + struct drm_gem_open gem_open; + int ret; + + printf("Testing error return on bad open ioctl.\n"); + + gem_open.name = 0x10101010; + ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &gem_open); + + assert(ret == -1 && errno == ENOENT); +} + +int main(int argc, char **argv) +{ + int fd; + + fd = drm_open_any(); + + test_flink(fd); + test_double_flink(fd); + test_bad_flink(fd); + test_bad_open(fd); + + return 0; +} diff --git a/tests/gem_gtt_concurrent_blit.c b/tests/gem_gtt_concurrent_blit.c new file mode 100644 index 00000000..c68af7b5 --- /dev/null +++ b/tests/gem_gtt_concurrent_blit.c @@ -0,0 +1,145 @@ +/* + * Copyright © 2009,2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** @file gem_cpu_concurrent_blit.c + * + * This is a test of GTT mmap read/write behavior when writing to active + * buffers. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static void +set_bo(drm_intel_bo *bo, uint32_t val, int width, int height) +{ + int size = width * height; + uint32_t *vaddr; + + drm_intel_gem_bo_start_gtt_access(bo, true); + vaddr = bo->virtual; + while (size--) + *vaddr++ = val; +} + +static void +cmp_bo(drm_intel_bo *bo, uint32_t val, int width, int height) +{ + int size = width * height; + uint32_t *vaddr; + + drm_intel_gem_bo_start_gtt_access(bo, false); + vaddr = bo->virtual; + while (size--) + assert(*vaddr++ == val); +} + +static drm_intel_bo * +create_bo(drm_intel_bufmgr *bufmgr, uint32_t val, int width, int height) +{ + drm_intel_bo *bo; + + bo = drm_intel_bo_alloc(bufmgr, "bo", 4*width*height, 0); + assert(bo); + + /* gtt map doesn't have a write parameter, so just keep the mapping + * around (to avoid the set_domain with the gtt write domain set) and + * manually tell the kernel when we start access the gtt. */ + drm_intel_gem_bo_map_gtt(bo); + + set_bo(bo, val, width, height); + + return bo; +} + +int +main(int argc, char **argv) +{ + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + int num_buffers = 128, max; + drm_intel_bo *src[128], *dst[128], *dummy; + int width = 512, height = 512; + int fd; + int i; + + fd = drm_open_any(); + + max = gem_aperture_size (fd) / (1024 * 1024) / 2; + if (num_buffers > max) + num_buffers = max; + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + for (i = 0; i < num_buffers; i++) { + src[i] = create_bo(bufmgr, i, width, height); + dst[i] = create_bo(bufmgr, ~i, width, height); + } + dummy = create_bo(bufmgr, 0, width, height); + + /* try to overwrite the source values */ + for (i = 0; i < num_buffers; i++) + intel_copy_bo(batch, dst[i], src[i], width, height); + for (i = num_buffers; i--; ) + set_bo(src[i], 0xdeadbeef, width, height); + for (i = 0; i < num_buffers; i++) + cmp_bo(dst[i], i, width, height); + + /* try to read the results before the copy completes */ + for (i = 0; i < num_buffers; i++) + intel_copy_bo(batch, dst[i], src[i], width, height); + for (i = num_buffers; i--; ) + cmp_bo(dst[i], 0xdeadbeef, width, height); + + /* and finally try to trick the kernel into loosing the pending write */ + for (i = num_buffers; i--; ) + set_bo(src[i], 0xabcdabcd, width, height); + for (i = 0; i < num_buffers; i++) + intel_copy_bo(batch, dst[i], src[i], width, height); + for (i = num_buffers; i--; ) + intel_copy_bo(batch, dummy, dst[i], width, height); + for (i = num_buffers; i--; ) + cmp_bo(dst[i], 0xabcdabcd, width, height); + + return 0; +} diff --git a/tests/gem_gtt_cpu_tlb.c b/tests/gem_gtt_cpu_tlb.c new file mode 100644 index 00000000..68533709 --- /dev/null +++ b/tests/gem_gtt_cpu_tlb.c @@ -0,0 +1,108 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +/** @file gem_gtt_cpu_tlb.c + * + * This test checks whether gtt tlbs for cpu access are correctly invalidated. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#define OBJ_SIZE (1024*1024) + +#define PAGE_SIZE 4096 + +static uint32_t +create_bo(int fd) +{ + uint32_t handle; + uint32_t *data; + int i; + + handle = gem_create(fd, OBJ_SIZE); + + /* Fill the BO with dwords starting at start_val */ + data = gem_mmap(fd, handle, OBJ_SIZE, PROT_READ | PROT_WRITE); + for (i = 0; i < OBJ_SIZE/4; i++) + data[i] = i; + munmap(data, OBJ_SIZE); + + return handle; +} + +int +main(int argc, char **argv) +{ + int fd; + int i; + uint32_t handle; + + uint32_t *ptr; + + fd = drm_open_any(); + + handle = gem_create(fd, OBJ_SIZE); + + /* touch one page */ + ptr = gem_mmap(fd, handle, OBJ_SIZE, PROT_READ | PROT_WRITE); + *ptr = 0xdeadbeef; + munmap(ptr, OBJ_SIZE); + + gem_close(fd, handle); + + /* stirr up the page allocator a bit. */ + ptr = malloc(OBJ_SIZE); + assert(ptr); + memset(ptr, 0x1, OBJ_SIZE); + + handle = create_bo(fd); + + /* Read a bunch of random subsets of the data and check that they come + * out right. + */ + gem_read(fd, handle, 0, ptr, OBJ_SIZE); + for (i = 0; i < OBJ_SIZE/4; i++) + assert(ptr[i] == i); + + close(fd); + + return 0; +} diff --git a/tests/gem_gtt_speed.c b/tests/gem_gtt_speed.c new file mode 100644 index 00000000..73a3c6dc --- /dev/null +++ b/tests/gem_gtt_speed.c @@ -0,0 +1,292 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +#define OBJECT_SIZE 16384 + +static double elapsed(const struct timeval *start, + const struct timeval *end, + int loop) +{ + return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop; +} + +int main(int argc, char **argv) +{ + struct timeval start, end; + uint8_t *buf; + uint32_t handle; + int size = OBJECT_SIZE; + int loop, i, tiling; + int fd; + + if (argc > 1) + size = atoi(argv[1]); + if (size == 0) { + fprintf(stderr, "Invalid object size specified\n"); + return 1; + } + + buf = malloc(size); + memset(buf, 0, size); + fd = drm_open_any(); + + handle = gem_create(fd, size); + assert(handle); + + for (tiling = I915_TILING_NONE; tiling <= I915_TILING_Y; tiling++) { + if (tiling != I915_TILING_NONE) { + printf("\nSetting tiling mode to %s\n", + tiling == I915_TILING_X ? "X" : "Y"); + gem_set_tiling(fd, handle, tiling, 512); + } + + if (tiling == I915_TILING_NONE) { + gem_set_domain(fd, handle, + I915_GEM_DOMAIN_CPU, + I915_GEM_DOMAIN_CPU); + + { + uint32_t *base = gem_mmap__cpu(fd, handle, size, PROT_READ | PROT_WRITE); + volatile uint32_t *ptr = base; + int x = 0; + + for (i = 0; i < size/sizeof(*ptr); i++) + x += ptr[i]; + + /* force overtly clever gcc to actually compute x */ + ptr[0] = x; + + munmap(base, size); + + /* mmap read */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) { + base = gem_mmap__cpu(fd, handle, size, PROT_READ | PROT_WRITE); + ptr = base; + x = 0; + + for (i = 0; i < size/sizeof(*ptr); i++) + x += ptr[i]; + + /* force overtly clever gcc to actually compute x */ + ptr[0] = x; + + munmap(base, size); + } + gettimeofday(&end, NULL); + printf("Time to read %dk through a CPU map: %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + /* mmap write */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) { + base = gem_mmap__cpu(fd, handle, size, PROT_READ | PROT_WRITE); + ptr = base; + + for (i = 0; i < size/sizeof(*ptr); i++) + ptr[i] = i; + + munmap(base, size); + } + gettimeofday(&end, NULL); + printf("Time to write %dk through a CPU map: %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + } + + /* CPU pwrite */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) + gem_write(fd, handle, 0, buf, size); + gettimeofday(&end, NULL); + printf("Time to pwrite %dk through the CPU: %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + /* CPU pread */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) + gem_read(fd, handle, 0, buf, size); + gettimeofday(&end, NULL); + printf("Time to pread %dk through the CPU: %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + } + + /* prefault into gtt */ + { + uint32_t *base = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE); + volatile uint32_t *ptr = base; + int x = 0; + + for (i = 0; i < size/sizeof(*ptr); i++) + x += ptr[i]; + + /* force overtly clever gcc to actually compute x */ + ptr[0] = x; + + munmap(base, size); + } + /* mmap read */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) { + uint32_t *base = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE); + volatile uint32_t *ptr = base; + int x = 0; + + for (i = 0; i < size/sizeof(*ptr); i++) + x += ptr[i]; + + /* force overtly clever gcc to actually compute x */ + ptr[0] = x; + + munmap(base, size); + } + gettimeofday(&end, NULL); + printf("Time to read %dk through a GTT map: %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + /* mmap write */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) { + uint32_t *base = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE); + volatile uint32_t *ptr = base; + + for (i = 0; i < size/sizeof(*ptr); i++) + ptr[i] = i; + + munmap(base, size); + } + gettimeofday(&end, NULL); + printf("Time to write %dk through a GTT map: %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + /* mmap read */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) { + uint32_t *base = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE); + volatile uint32_t *ptr = base; + int x = 0; + + for (i = 0; i < size/sizeof(*ptr); i++) + x += ptr[i]; + + /* force overtly clever gcc to actually compute x */ + ptr[0] = x; + + munmap(base, size); + } + gettimeofday(&end, NULL); + printf("Time to read %dk (again) through a GTT map: %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + if (tiling == I915_TILING_NONE) { + /* GTT pwrite */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) + gem_write(fd, handle, 0, buf, size); + gettimeofday(&end, NULL); + printf("Time to pwrite %dk through the GTT: %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + /* GTT pread */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) + gem_read(fd, handle, 0, buf, size); + gettimeofday(&end, NULL); + printf("Time to pread %dk through the GTT: %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + /* GTT pwrite, including clflush */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) { + gem_write(fd, handle, 0, buf, size); + gem_sync(fd, handle); + } + gettimeofday(&end, NULL); + printf("Time to pwrite %dk through the GTT (clflush): %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + /* GTT pread, including clflush */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) { + gem_sync(fd, handle); + gem_read(fd, handle, 0, buf, size); + } + gettimeofday(&end, NULL); + printf("Time to pread %dk through the GTT (clflush): %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + /* partial writes */ + printf("Now partial writes.\n"); + size /= 4; + + /* partial GTT pwrite, including clflush */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) { + gem_write(fd, handle, 0, buf, size); + gem_sync(fd, handle); + } + gettimeofday(&end, NULL); + printf("Time to pwrite %dk through the GTT (clflush): %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + /* partial GTT pread, including clflush */ + gettimeofday(&start, NULL); + for (loop = 0; loop < 1000; loop++) { + gem_sync(fd, handle); + gem_read(fd, handle, 0, buf, size); + } + gettimeofday(&end, NULL); + printf("Time to pread %dk through the GTT (clflush): %7.3fµs\n", + size/1024, elapsed(&start, &end, loop)); + + size *= 4; + } + + } + + gem_close(fd, handle); + close(fd); + + return 0; +} diff --git a/tests/gem_hang.c b/tests/gem_hang.c new file mode 100644 index 00000000..f9db3400 --- /dev/null +++ b/tests/gem_hang.c @@ -0,0 +1,97 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static int bad_pipe; + +static void +gpu_hang(void) +{ + int cmd; + + cmd = bad_pipe ? MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW : + MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; + + BEGIN_BATCH(6); + /* The documentation says that the LOAD_SCAN_LINES command + * always comes in pairs. Don't ask me why. */ + OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | (bad_pipe << 20)); + OUT_BATCH((0 << 16) | 2048); + OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | (bad_pipe << 20)); + OUT_BATCH((0 << 16) | 2048); + OUT_BATCH(MI_WAIT_FOR_EVENT | cmd); + OUT_BATCH(MI_NOOP); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); +} + +int main(int argc, char **argv) +{ + int fd; + + if (argc != 2) { + fprintf(stderr, "usage: %s <disabled pipe number>\n", + argv[0]); + exit(-1); + } + + bad_pipe = atoi(argv[1]); + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + gpu_hang(); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_hangcheck_forcewake.c b/tests/gem_hangcheck_forcewake.c new file mode 100644 index 00000000..96a30fef --- /dev/null +++ b/tests/gem_hangcheck_forcewake.c @@ -0,0 +1,127 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +/* + * Testcase: Provoke the hangcheck timer on an otherwise idle system + * + * This tries to hit forcewake locking bugs when the hangcheck runs. Somehow we + * often luck out and the hangcheck runs while someone else is already holding + * the dev->struct_mutex. + * + * It's imperative that nothing else runs while this test runs, i.e. kill your X + * session, please. + */ + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +uint32_t blob[2048*2048]; + +#define MAX_BLT_SIZE 128 +int main(int argc, char **argv) +{ + drm_intel_bo *bo = NULL; + uint32_t tiling_mode = I915_TILING_X; + unsigned long pitch, act_size; + int fd, i, devid; + + memset(blob, 'A', sizeof(blob)); + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + devid = intel_get_drm_devid(fd); + batch = intel_batchbuffer_alloc(bufmgr, devid); + + act_size = 2048; + printf("filling ring\n"); + drm_intel_bo_unreference(bo); + bo = drm_intel_bo_alloc_tiled(bufmgr, "tiled bo", act_size, act_size, + 4, &tiling_mode, &pitch, 0); + + drm_intel_bo_subdata(bo, 0, act_size*act_size*4, blob); + + if (IS_965(devid)) + pitch /= 4; + + for (i = 0; i < 10000; i++) { + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB | + XY_SRC_COPY_BLT_SRC_TILED | + XY_SRC_COPY_BLT_DST_TILED); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + pitch); + OUT_BATCH(0 << 16 | 1024); + OUT_BATCH((2048) << 16 | (2048)); + OUT_RELOC_FENCED(bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(pitch); + OUT_RELOC_FENCED(bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + if (IS_GEN6(devid) || IS_GEN7(devid)) { + BEGIN_BATCH(3); + OUT_BATCH(XY_SETUP_CLIP_BLT_CMD); + OUT_BATCH(0); + OUT_BATCH(0); + ADVANCE_BATCH(); + } + } + + printf("waiting\n"); + sleep(10); + + printf("done waiting, check dmesg\n"); + drm_intel_bo_unreference(bo); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_largeobject.c b/tests/gem_largeobject.c new file mode 100644 index 00000000..163bf101 --- /dev/null +++ b/tests/gem_largeobject.c @@ -0,0 +1,95 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Jesse Barnes <jbarnes@virtuousgeek.org> + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +/* Should take 64 pages to store the page pointers on 64 bit */ +#define OBJ_SIZE (128 * 1024 * 1024) + +unsigned char data[OBJ_SIZE]; + +static void +test_large_object(int fd) +{ + struct drm_i915_gem_create create; + struct drm_i915_gem_pin pin; + uint32_t obj_size; + int ret; + + memset(&create, 0, sizeof(create)); + memset(&pin, 0, sizeof(pin)); + + if (gem_aperture_size(fd)*3/4 < OBJ_SIZE/2) + obj_size = OBJ_SIZE / 4; + else if (gem_aperture_size(fd)*3/4 < OBJ_SIZE) + obj_size = OBJ_SIZE / 2; + else + obj_size = OBJ_SIZE; + create.size = obj_size; + printf("obj size %i\n", obj_size); + + ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); + if (ret) { + fprintf(stderr, "object creation failed: %s\n", + strerror(errno)); + exit(ret); + } + + pin.handle = create.handle; + ret = ioctl(fd, DRM_IOCTL_I915_GEM_PIN, &pin); + if (ret) { + fprintf(stderr, "pin failed: %s\n", + strerror(errno)); + exit(ret); + } + + gem_write(fd, create.handle, 0, data, obj_size); + + /* kernel should clean this up for us */ +} + +int main(int argc, char **argv) +{ + int fd; + + fd = drm_open_any(); + + test_large_object(fd); + + return 0; +} diff --git a/tests/gem_linear_blits.c b/tests/gem_linear_blits.c new file mode 100644 index 00000000..fe15f1d1 --- /dev/null +++ b/tests/gem_linear_blits.c @@ -0,0 +1,250 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** @file gem_linear_blits.c + * + * This is a test of doing many blits, with a working set + * larger than the aperture size. + * + * The goal is to simply ensure the basics work. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +#define WIDTH 512 +#define HEIGHT 512 + +static uint32_t linear[WIDTH*HEIGHT]; + +static void +copy(int fd, uint32_t dst, uint32_t src) +{ + uint32_t batch[10]; + struct drm_i915_gem_relocation_entry reloc[2]; + struct drm_i915_gem_exec_object2 obj[3]; + struct drm_i915_gem_execbuffer2 exec; + uint32_t handle; + int ret; + + batch[0] = XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB; + batch[1] = (3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + WIDTH*4; + batch[2] = 0; /* dst x1,y1 */ + batch[3] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */ + batch[4] = 0; /* dst reloc */ + batch[5] = 0; /* src x1,y1 */ + batch[6] = WIDTH*4; + batch[7] = 0; /* src reloc */ + batch[8] = MI_BATCH_BUFFER_END; + batch[9] = MI_NOOP; + + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, sizeof(batch)); + + reloc[0].target_handle = dst; + reloc[0].delta = 0; + reloc[0].offset = 4 * sizeof(batch[0]); + reloc[0].presumed_offset = 0; + reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;; + reloc[0].write_domain = I915_GEM_DOMAIN_RENDER; + + reloc[1].target_handle = src; + reloc[1].delta = 0; + reloc[1].offset = 7 * sizeof(batch[0]); + reloc[1].presumed_offset = 0; + reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;; + reloc[1].write_domain = 0; + + obj[0].handle = dst; + obj[0].relocation_count = 0; + obj[0].relocs_ptr = 0; + obj[0].alignment = 0; + obj[0].offset = 0; + obj[0].flags = 0; + obj[0].rsvd1 = 0; + obj[0].rsvd2 = 0; + + obj[1].handle = src; + obj[1].relocation_count = 0; + obj[1].relocs_ptr = 0; + obj[1].alignment = 0; + obj[1].offset = 0; + obj[1].flags = 0; + obj[1].rsvd1 = 0; + obj[1].rsvd2 = 0; + + obj[2].handle = handle; + obj[2].relocation_count = 2; + obj[2].relocs_ptr = (uintptr_t)reloc; + obj[2].alignment = 0; + obj[2].offset = 0; + obj[2].flags = 0; + obj[2].rsvd1 = obj[2].rsvd2 = 0; + + exec.buffers_ptr = (uintptr_t)obj; + exec.buffer_count = 3; + exec.batch_start_offset = 0; + exec.batch_len = sizeof(batch); + exec.DR1 = exec.DR4 = 0; + exec.num_cliprects = 0; + exec.cliprects_ptr = 0; + exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0; + i915_execbuffer2_set_context_id(exec, 0); + exec.rsvd2 = 0; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + while (ret && errno == EBUSY) { + drmCommandNone(fd, DRM_I915_GEM_THROTTLE); + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + } + assert(ret == 0); + + gem_close(fd, handle); +} + +static uint32_t +create_bo(int fd, uint32_t val) +{ + uint32_t handle; + int i; + + handle = gem_create(fd, sizeof(linear)); + + /* Fill the BO with dwords starting at val */ + for (i = 0; i < WIDTH*HEIGHT; i++) + linear[i] = val++; + gem_write(fd, handle, 0, linear, sizeof(linear)); + + return handle; +} + +static void +check_bo(int fd, uint32_t handle, uint32_t val) +{ + int i; + + gem_read(fd, handle, 0, linear, sizeof(linear)); + for (i = 0; i < WIDTH*HEIGHT; i++) { + if (linear[i] != val) { + fprintf(stderr, "Expected 0x%08x, found 0x%08x " + "at offset 0x%08x\n", + val, linear[i], i * 4); + abort(); + } + val++; + } +} + +int main(int argc, char **argv) +{ + uint32_t *handle, *start_val; + uint32_t start = 0; + int i, fd, count; + + fd = drm_open_any(); + + count = 0; + if (argc > 1) + count = atoi(argv[1]); + if (count == 0) + count = 3 * gem_aperture_size(fd) / (1024*1024) / 2; + + if (count > intel_get_total_ram_mb() * 9 / 10) { + count = intel_get_total_ram_mb() * 9 / 10; + printf("not enough RAM to run test, reducing buffer count\n"); + } + + printf("Using %d 1MiB buffers\n", count); + + handle = malloc(sizeof(uint32_t)*count*2); + start_val = handle + count; + + for (i = 0; i < count; i++) { + handle[i] = create_bo(fd, start); + start_val[i] = start; + start += 1024 * 1024 / 4; + } + + printf("Verifying initialisation...\n"); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + printf("Cyclic blits, forward...\n"); + for (i = 0; i < count * 4; i++) { + int src = i % count; + int dst = (i + 1) % count; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + printf("Cyclic blits, backward...\n"); + for (i = 0; i < count * 4; i++) { + int src = (i + 1) % count; + int dst = i % count; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + printf("Random blits...\n"); + for (i = 0; i < count * 4; i++) { + int src = random() % count; + int dst = random() % count; + + if (src == dst) + continue; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + return 0; +} diff --git a/tests/gem_mmap.c b/tests/gem_mmap.c new file mode 100644 index 00000000..f9369f43 --- /dev/null +++ b/tests/gem_mmap.c @@ -0,0 +1,96 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +#define OBJECT_SIZE 16384 + +int main(int argc, char **argv) +{ + int fd; + struct drm_i915_gem_mmap arg; + uint8_t expected[OBJECT_SIZE]; + uint8_t buf[OBJECT_SIZE]; + uint8_t *addr; + int ret; + int handle; + + fd = drm_open_any(); + + memset(&arg, 0, sizeof(arg)); + arg.handle = 0x10101010; + arg.offset = 0; + arg.size = 4096; + printf("Testing mmaping of bad object.\n"); + ret = ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &arg); + assert(ret == -1 && errno == ENOENT); + + handle = gem_create(fd, OBJECT_SIZE); + + printf("Testing mmaping of newly created object.\n"); + arg.handle = handle; + arg.offset = 0; + arg.size = OBJECT_SIZE; + ret = ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &arg); + assert(ret == 0); + addr = (uint8_t *)(uintptr_t)arg.addr_ptr; + + printf("Testing contents of newly created object.\n"); + memset(expected, 0, sizeof(expected)); + assert(memcmp(addr, expected, sizeof(expected)) == 0); + + printf("Testing coherency of writes and mmap reads.\n"); + memset(buf, 0, sizeof(buf)); + memset(buf + 1024, 0x01, 1024); + memset(expected + 1024, 0x01, 1024); + gem_write(fd, handle, 0, buf, OBJECT_SIZE); + assert(memcmp(buf, addr, sizeof(buf)) == 0); + + printf("Testing that mapping stays after close\n"); + gem_close(fd, handle); + assert(memcmp(buf, addr, sizeof(buf)) == 0); + + printf("Testing unmapping\n"); + munmap(addr, OBJECT_SIZE); + + close(fd); + + return 0; +} diff --git a/tests/gem_mmap_gtt.c b/tests/gem_mmap_gtt.c new file mode 100644 index 00000000..e7a48679 --- /dev/null +++ b/tests/gem_mmap_gtt.c @@ -0,0 +1,161 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +#define OBJECT_SIZE (16*1024*1024) + +static void set_domain(int fd, uint32_t handle) +{ + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); +} + +static void * +mmap_bo(int fd, uint32_t handle) +{ + void *ptr; + + ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE); + assert(ptr != MAP_FAILED); + + return ptr; +} + +static void * +create_pointer(int fd) +{ + uint32_t handle; + void *ptr; + + handle = gem_create(fd, OBJECT_SIZE); + + ptr = mmap_bo(fd, handle); + + gem_close(fd, handle); + + return ptr; +} + +static void +test_copy(int fd) +{ + void *src, *dst; + + /* copy from a fresh src to fresh dst to force pagefault on both */ + src = create_pointer(fd); + dst = create_pointer(fd); + + memcpy(dst, src, OBJECT_SIZE); + memcpy(src, dst, OBJECT_SIZE); + + munmap(dst, OBJECT_SIZE); + munmap(src, OBJECT_SIZE); +} + +static void +test_write(int fd) +{ + void *src; + uint32_t dst; + + /* copy from a fresh src to fresh dst to force pagefault on both */ + src = create_pointer(fd); + dst = gem_create(fd, OBJECT_SIZE); + + gem_write(fd, dst, 0, src, OBJECT_SIZE); + + gem_close(fd, dst); + munmap(src, OBJECT_SIZE); +} + +static void +test_write_gtt(int fd) +{ + uint32_t dst; + char *dst_gtt; + void *src; + + dst = gem_create(fd, OBJECT_SIZE); + + /* prefault object into gtt */ + dst_gtt = mmap_bo(fd, dst); + set_domain(fd, dst); + memset(dst_gtt, 0, OBJECT_SIZE); + munmap(dst_gtt, OBJECT_SIZE); + + src = create_pointer(fd); + + gem_write(fd, dst, 0, src, OBJECT_SIZE); + + gem_close(fd, dst); + munmap(src, OBJECT_SIZE); +} + +static void +test_read(int fd) +{ + void *dst; + uint32_t src; + + /* copy from a fresh src to fresh dst to force pagefault on both */ + dst = create_pointer(fd); + src = gem_create(fd, OBJECT_SIZE); + + gem_read(fd, src, 0, dst, OBJECT_SIZE); + + gem_close(fd, src); + munmap(dst, OBJECT_SIZE); +} + +int main(int argc, char **argv) +{ + int fd; + + fd = drm_open_any(); + + test_copy(fd); + test_read(fd); + test_write(fd); + test_write_gtt(fd); + + close(fd); + + return 0; +} diff --git a/tests/gem_mmap_offset_exhaustion.c b/tests/gem_mmap_offset_exhaustion.c new file mode 100644 index 00000000..51ae5990 --- /dev/null +++ b/tests/gem_mmap_offset_exhaustion.c @@ -0,0 +1,96 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +#define OBJECT_SIZE (1024*1024) + +/* Testcase: checks whether the kernel handles mmap offset exhaustion correctly + * + * Currently the kernel doesn't reap the mmap offset of purged objects, albeit + * there's nothing that prevents it ABI-wise and it helps to get out of corners + * (because drm_mm is only 32bit on 32bit archs unfortunately. + * + * Note that on 64bit machines we have plenty of address space (because drm_mm + * uses unsigned long). + */ + +static void +create_and_map_bo(int fd) +{ + uint32_t handle; + char *ptr; + + handle = gem_create(fd, OBJECT_SIZE); + + ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE); + + if (!ptr) { + fprintf(stderr, "mmap failed\n"); + assert(ptr); + } + + /* touch it to force it into the gtt */ + *ptr = 0; + + /* but then unmap it again because we only have limited address space on + * 32 bit */ + munmap(ptr, OBJECT_SIZE); + + /* we happily leak objects to exhaust mmap offset space, the kernel will + * reap backing storage. */ + gem_madvise(fd, handle, I915_MADV_DONTNEED); +} + +int main(int argc, char **argv) +{ + int fd, i; + + fd = drm_open_any(); + + /* we have 32bit of address space, so try to fit one MB more + * than that. */ + for (i = 0; i < 4096 + 1; i++) + create_and_map_bo(fd); + + close(fd); + + return 0; +} diff --git a/tests/gem_partial_pwrite_pread.c b/tests/gem_partial_pwrite_pread.c new file mode 100644 index 00000000..5c8f6f5f --- /dev/null +++ b/tests/gem_partial_pwrite_pread.c @@ -0,0 +1,263 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +/* + * Testcase: pwrite/pread consistency when touching partial cachelines + * + * Some fancy new pwrite/pread optimizations clflush in-line while + * reading/writing. Check whether all required clflushes happen. + * + */ + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +drm_intel_bo *scratch_bo; +drm_intel_bo *staging_bo; +#define BO_SIZE (4*4096) +uint32_t devid; +uint64_t mappable_gtt_limit; +int fd; + +static void +copy_bo(drm_intel_bo *src, drm_intel_bo *dst) +{ + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + 4096); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH((BO_SIZE/4096) << 16 | 1024); + OUT_RELOC_FENCED(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(4096); + OUT_RELOC_FENCED(src, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); +} + +static void +blt_bo_fill(drm_intel_bo *tmp_bo, drm_intel_bo *bo, int val) +{ + uint8_t *gtt_ptr; + int i; + + drm_intel_gem_bo_map_gtt(tmp_bo); + gtt_ptr = tmp_bo->virtual; + + for (i = 0; i < BO_SIZE; i++) + gtt_ptr[i] = val; + + drm_intel_gem_bo_unmap_gtt(tmp_bo); + + if (bo->offset < mappable_gtt_limit && + (IS_G33(devid) || intel_gen(devid) >= 4)) + drmtest_trash_aperture(); + + copy_bo(tmp_bo, bo); +} + +#define MAX_BLT_SIZE 128 +#define ROUNDS 1000 +int main(int argc, char **argv) +{ + int i, j; + uint8_t tmp[BO_SIZE]; + uint8_t *gtt_ptr; + + srandom(0xdeadbeef); + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + //drm_intel_bufmgr_gem_enable_reuse(bufmgr); + devid = intel_get_drm_devid(fd); + batch = intel_batchbuffer_alloc(bufmgr, devid); + + /* overallocate the buffers we're actually using because */ + scratch_bo = drm_intel_bo_alloc(bufmgr, "scratch bo", BO_SIZE, 4096); + staging_bo = drm_intel_bo_alloc(bufmgr, "staging bo", BO_SIZE, 4096); + + drmtest_init_aperture_trashers(bufmgr); + mappable_gtt_limit = gem_mappable_aperture_size(); + + printf("checking partial reads\n"); + for (i = 0; i < ROUNDS; i++) { + int start, len; + int val = i % 256; + + blt_bo_fill(staging_bo, scratch_bo, i); + + start = random() % BO_SIZE; + len = random() % (BO_SIZE-start) + 1; + + drm_intel_bo_get_subdata(scratch_bo, start, len, tmp); + for (j = 0; j < len; j++) { + if (tmp[j] != val) { + printf("mismatch at %i, got: %i, expected: %i\n", + j, tmp[j], val); + exit(1); + } + } + + drmtest_progress("partial reads test: ", i, ROUNDS); + } + + printf("checking partial writes\n"); + for (i = 0; i < ROUNDS; i++) { + int start, len; + int val = i % 256; + + blt_bo_fill(staging_bo, scratch_bo, i); + + start = random() % BO_SIZE; + len = random() % (BO_SIZE-start) + 1; + + memset(tmp, i + 63, BO_SIZE); + + drm_intel_bo_subdata(scratch_bo, start, len, tmp); + + copy_bo(scratch_bo, staging_bo); + drm_intel_gem_bo_map_gtt(staging_bo); + gtt_ptr = staging_bo->virtual; + + for (j = 0; j < start; j++) { + if (gtt_ptr[j] != val) { + printf("mismatch at %i, got: %i, expected: %i\n", + j, tmp[j], val); + exit(1); + } + } + for (; j < start + len; j++) { + if (gtt_ptr[j] != tmp[0]) { + printf("mismatch at %i, got: %i, expected: %i\n", + j, tmp[j], i); + exit(1); + } + } + for (; j < BO_SIZE; j++) { + if (gtt_ptr[j] != val) { + printf("mismatch at %i, got: %i, expected: %i\n", + j, tmp[j], val); + exit(1); + } + } + drm_intel_gem_bo_unmap_gtt(staging_bo); + + drmtest_progress("partial writes test: ", i, ROUNDS); + } + + printf("checking partial writes after partial reads\n"); + for (i = 0; i < ROUNDS; i++) { + int start, len; + int val = i % 256; + + blt_bo_fill(staging_bo, scratch_bo, i); + + /* partial read */ + start = random() % BO_SIZE; + len = random() % (BO_SIZE-start) + 1; + + drm_intel_bo_get_subdata(scratch_bo, start, len, tmp); + for (j = 0; j < len; j++) { + if (tmp[j] != val) { + printf("mismatch in read at %i, got: %i, expected: %i\n", + j, tmp[j], val); + exit(1); + } + } + + /* Change contents through gtt to make the pread cachelines + * stale. */ + val = (i + 17) % 256; + blt_bo_fill(staging_bo, scratch_bo, val); + + /* partial write */ + start = random() % BO_SIZE; + len = random() % (BO_SIZE-start) + 1; + + memset(tmp, i + 63, BO_SIZE); + + drm_intel_bo_subdata(scratch_bo, start, len, tmp); + + copy_bo(scratch_bo, staging_bo); + drm_intel_gem_bo_map_gtt(staging_bo); + gtt_ptr = staging_bo->virtual; + + for (j = 0; j < start; j++) { + if (gtt_ptr[j] != val) { + printf("mismatch at %i, got: %i, expected: %i\n", + j, tmp[j], val); + exit(1); + } + } + for (; j < start + len; j++) { + if (gtt_ptr[j] != tmp[0]) { + printf("mismatch at %i, got: %i, expected: %i\n", + j, tmp[j], tmp[0]); + exit(1); + } + } + for (; j < BO_SIZE; j++) { + if (gtt_ptr[j] != val) { + printf("mismatch at %i, got: %i, expected: %i\n", + j, tmp[j], val); + exit(1); + } + } + drm_intel_gem_bo_unmap_gtt(staging_bo); + + drmtest_progress("partial read/writes test: ", i, ROUNDS); + } + + drmtest_cleanup_aperture_trashers(); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_pipe_control_store_loop.c b/tests/gem_pipe_control_store_loop.c new file mode 100644 index 00000000..e03cddd7 --- /dev/null +++ b/tests/gem_pipe_control_store_loop.c @@ -0,0 +1,184 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> (based on gem_storedw_*.c) + * + */ + +/* + * Testcase: (TLB-)Coherency of pipe_control QW writes + * + * Writes a counter-value into an always newly allocated target bo (by disabling + * buffer reuse). Decently trashes on tlb inconsistencies, too. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +uint32_t devid; + +#define GFX_OP_PIPE_CONTROL ((0x3<<29)|(0x3<<27)|(0x2<<24)|2) +#define PIPE_CONTROL_WRITE_IMMEDIATE (1<<14) +#define PIPE_CONTROL_WRITE_TIMESTAMP (3<<14) +#define PIPE_CONTROL_DEPTH_STALL (1<<13) +#define PIPE_CONTROL_WC_FLUSH (1<<12) +#define PIPE_CONTROL_IS_FLUSH (1<<11) /* MBZ on Ironlake */ +#define PIPE_CONTROL_TC_FLUSH (1<<10) /* GM45+ only */ +#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1<<1) +#define PIPE_CONTROL_CS_STALL (1<<20) +#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */ + +/* Like the store dword test, but we create new command buffers each time */ +static void +store_pipe_control_loop(void) +{ + int i, val = 0; + uint32_t *buf; + drm_intel_bo *target_bo; + + for (i = 0; i < 0x10000; i++) { + /* we want to check tlb consistency of the pipe_control target, + * so get a new buffer every time around */ + target_bo = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096); + if (!target_bo) { + fprintf(stderr, "failed to alloc target buffer\n"); + exit(-1); + } + + /* gem_storedw_batches_loop.c is a bit overenthusiastic with + * creating new batchbuffers - with buffer reuse disabled, the + * support code will do that for us. */ + if (intel_gen(devid) >= 6) { + /* work-around hw issue, see intel_emit_post_sync_nonzero_flush + * in mesa sources. */ + BEGIN_BATCH(4); + OUT_BATCH(GFX_OP_PIPE_CONTROL); + OUT_BATCH(PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_STALL_AT_SCOREBOARD); + OUT_BATCH(0); /* address */ + OUT_BATCH(0); /* write data */ + ADVANCE_BATCH(); + + BEGIN_BATCH(4); + OUT_BATCH(GFX_OP_PIPE_CONTROL); + OUT_BATCH(PIPE_CONTROL_WRITE_IMMEDIATE); + OUT_RELOC(target_bo, + I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, + PIPE_CONTROL_GLOBAL_GTT); + OUT_BATCH(val); /* write data */ + ADVANCE_BATCH(); + } else if (intel_gen(devid) >= 4) { + BEGIN_BATCH(4); + OUT_BATCH(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_WC_FLUSH | + PIPE_CONTROL_TC_FLUSH | + PIPE_CONTROL_WRITE_IMMEDIATE | 2); + OUT_RELOC(target_bo, + I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, + PIPE_CONTROL_GLOBAL_GTT); + OUT_BATCH(val); + OUT_BATCH(0xdeadbeef); + ADVANCE_BATCH(); + } + + intel_batchbuffer_flush_on_ring(batch, 0); + + drm_intel_bo_map(target_bo, 1); + + buf = target_bo->virtual; + if (buf[0] != val) { + fprintf(stderr, + "value mismatch: cur 0x%08x, stored 0x%08x\n", + buf[0], val); + exit(-1); + } + buf[0] = 0; /* let batch write it again */ + drm_intel_bo_unmap(target_bo); + + drm_intel_bo_unreference(target_bo); + + val++; + } + + printf("completed %d writes successfully\n", i); +} + +int main(int argc, char **argv) +{ + int fd; + + if (argc != 1) { + fprintf(stderr, "usage: %s\n", argv[0]); + exit(-1); + } + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + if (!bufmgr) { + fprintf(stderr, "failed to init libdrm\n"); + exit(-1); + } + + if (IS_GEN2(devid) || IS_GEN3(devid)) { + fprintf(stderr, "no pipe_control on gen2/3\n"); + return 77; + } + if (devid == PCI_CHIP_I965_G) { + fprintf(stderr, "pipe_control totally broken on i965\n"); + return 77; + } + /* IMPORTANT: No call to + * drm_intel_bufmgr_gem_enable_reuse(bufmgr); + * here because we wan't to have fresh buffers (to trash the tlb) + * every time! */ + + batch = intel_batchbuffer_alloc(bufmgr, devid); + if (!batch) { + fprintf(stderr, "failed to create batch buffer\n"); + exit(-1); + } + + store_pipe_control_loop(); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_pread_after_blit.c b/tests/gem_pread_after_blit.c new file mode 100644 index 00000000..c9c8b02c --- /dev/null +++ b/tests/gem_pread_after_blit.c @@ -0,0 +1,175 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** @file gem_pread_after_blit.c + * + * This is a test of pread's behavior when getting values out of just-drawn-to + * buffers. + * + * The goal is to catch failure in the whole-buffer-flush or + * ranged-buffer-flush paths in the kernel. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static const int width = 512, height = 512; +static const int size = 1024 * 1024; + +#define PAGE_SIZE 4096 + +static drm_intel_bo * +create_bo(uint32_t val) +{ + drm_intel_bo *bo; + uint32_t *vaddr; + int i; + + bo = drm_intel_bo_alloc(bufmgr, "src bo", size, 4096); + + /* Fill the BO with dwords starting at start_val */ + drm_intel_bo_map(bo, 1); + vaddr = bo->virtual; + + for (i = 0; i < 1024 * 1024 / 4; i++) + vaddr[i] = val++; + + drm_intel_bo_unmap(bo); + + return bo; +} + +static void +verify_large_read(drm_intel_bo *bo, uint32_t val) +{ + uint32_t buf[size / 4]; + int i; + + drm_intel_bo_get_subdata(bo, 0, size, buf); + + for (i = 0; i < size / 4; i++) { + if (buf[i] != val) { + fprintf(stderr, + "Unexpected value 0x%08x instead of " + "0x%08x at offset 0x%08x (%p)\n", + buf[i], val, i * 4, buf); + abort(); + } + val++; + } +} + +/** This reads at the size that Mesa usees for software fallbacks. */ +static void +verify_small_read(drm_intel_bo *bo, uint32_t val) +{ + uint32_t buf[4096 / 4]; + int offset, i; + + for (i = 0; i < 4096 / 4; i++) + buf[i] = 0x00c0ffee; + + for (offset = 0; offset < size; offset += PAGE_SIZE) { + drm_intel_bo_get_subdata(bo, offset, PAGE_SIZE, buf); + + for (i = 0; i < PAGE_SIZE; i += 4) { + if (buf[i / 4] != val) { + fprintf(stderr, + "Unexpected value 0x%08x instead of " + "0x%08x at offset 0x%08x\n", + buf[i / 4], val, i * 4); + abort(); + } + val++; + } + } +} + +int +main(int argc, char **argv) +{ + int fd; + drm_intel_bo *src1, *src2, *bo; + uint32_t start1 = 0; + uint32_t start2 = 1024 * 1024 / 4; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + src1 = create_bo(start1); + src2 = create_bo(start2); + + bo = drm_intel_bo_alloc(bufmgr, "dst bo", size, 4096); + + /* First, do a full-buffer read after blitting */ + printf("Large read after blit 1\n"); + intel_copy_bo(batch, bo, src1, width, height); + verify_large_read(bo, start1); + printf("Large read after blit 2\n"); + intel_copy_bo(batch, bo, src2, width, height); + verify_large_read(bo, start2); + + printf("Small reads after blit 1\n"); + intel_copy_bo(batch, bo, src1, width, height); + verify_small_read(bo, start1); + printf("Small reads after blit 2\n"); + intel_copy_bo(batch, bo, src2, width, height); + verify_small_read(bo, start2); + + printf("Large read after blit 3\n"); + intel_copy_bo(batch, bo, src1, width, height); + verify_large_read(bo, start1); + + drm_intel_bo_unreference(src1); + drm_intel_bo_unreference(src2); + drm_intel_bo_unreference(bo); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_pwrite.c b/tests/gem_pwrite.c new file mode 100644 index 00000000..051ed3b5 --- /dev/null +++ b/tests/gem_pwrite.c @@ -0,0 +1,122 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +#define OBJECT_SIZE 16384 + +#define COPY_BLT_CMD (2<<29|0x53<<22|0x6) +#define BLT_WRITE_ALPHA (1<<21) +#define BLT_WRITE_RGB (1<<20) +#define BLT_SRC_TILED (1<<15) +#define BLT_DST_TILED (1<<11) +#define MI_BATCH_BUFFER_END (0xA<<23) + +static void do_gem_write(int fd, uint32_t handle, void *buf, int len, int loops) +{ + while (loops--) + gem_write(fd, handle, 0, buf, len); +} + +static double elapsed(const struct timeval *start, + const struct timeval *end, + int loop) +{ + return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop; +} + +static const char *bytes_per_sec(char *buf, double v) +{ + const char *order[] = { + "", + "KiB", + "MiB", + "GiB", + "TiB", + NULL, + }, **o = order; + + while (v > 1000 && o[1]) { + v /= 1000; + o++; + } + sprintf(buf, "%.1f%s/s", v, *o); + return buf; +} + + +int main(int argc, char **argv) +{ + int object_size = 0; + uint32_t buf[20]; + uint32_t *src, dst; + int fd, count; + + if (argc > 1) + object_size = atoi(argv[1]); + if (object_size == 0) + object_size = OBJECT_SIZE; + object_size = (object_size + 3) & -4; + + fd = drm_open_any(); + + dst = gem_create(fd, object_size); + src = malloc(object_size); + for (count = 1; count <= 1<<17; count <<= 1) { + struct timeval start, end; + + gettimeofday(&start, NULL); + do_gem_write(fd, dst, src, object_size, count); + gettimeofday(&end, NULL); + printf("Time to pwrite %d bytes x %6d: %7.3fµs, %s\n", + object_size, count, + elapsed(&start, &end, count), + bytes_per_sec((char *)buf, object_size/elapsed(&start, &end, count)*1e6)); + fflush(stdout); + } + free(src); + gem_close(fd, dst); + + close(fd); + + return 0; +} diff --git a/tests/gem_readwrite.c b/tests/gem_readwrite.c new file mode 100644 index 00000000..68c3ff28 --- /dev/null +++ b/tests/gem_readwrite.c @@ -0,0 +1,134 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +#define OBJECT_SIZE 16384 + +static int +do_read(int fd, int handle, void *buf, int offset, int size) +{ + struct drm_i915_gem_pread read; + + /* Ensure that we don't have any convenient data in buf in case + * we fail. + */ + memset(buf, 0xd0, size); + + memset(&read, 0, sizeof(read)); + read.handle = handle; + read.data_ptr = (uintptr_t)buf; + read.size = size; + read.offset = offset; + + return ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &read); +} + +static int +do_write(int fd, int handle, void *buf, int offset, int size) +{ + struct drm_i915_gem_pwrite write; + + memset(&write, 0, sizeof(write)); + write.handle = handle; + write.data_ptr = (uintptr_t)buf; + write.size = size; + write.offset = offset; + + return ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &write); +} + +int main(int argc, char **argv) +{ + int fd; + uint8_t expected[OBJECT_SIZE]; + uint8_t buf[OBJECT_SIZE]; + int ret; + int handle; + + fd = drm_open_any(); + + handle = gem_create(fd, OBJECT_SIZE); + + printf("Testing contents of newly created object.\n"); + ret = do_read(fd, handle, buf, 0, OBJECT_SIZE); + assert(ret == 0); + memset(&expected, 0, sizeof(expected)); + assert(memcmp(expected, buf, sizeof(expected)) == 0); + + printf("Testing read beyond end of buffer.\n"); + ret = do_read(fd, handle, buf, OBJECT_SIZE / 2, OBJECT_SIZE); + assert(ret == -1 && errno == EINVAL); + + printf("Testing full write of buffer\n"); + memset(buf, 0, sizeof(buf)); + memset(buf + 1024, 0x01, 1024); + memset(expected + 1024, 0x01, 1024); + ret = do_write(fd, handle, buf, 0, OBJECT_SIZE); + assert(ret == 0); + ret = do_read(fd, handle, buf, 0, OBJECT_SIZE); + assert(ret == 0); + assert(memcmp(buf, expected, sizeof(buf)) == 0); + + printf("Testing partial write of buffer\n"); + memset(buf + 4096, 0x02, 1024); + memset(expected + 4096, 0x02, 1024); + ret = do_write(fd, handle, buf + 4096, 4096, 1024); + assert(ret == 0); + ret = do_read(fd, handle, buf, 0, OBJECT_SIZE); + assert(ret == 0); + assert(memcmp(buf, expected, sizeof(buf)) == 0); + + printf("Testing partial read of buffer\n"); + ret = do_read(fd, handle, buf, 512, 1024); + assert(ret == 0); + assert(memcmp(buf, expected + 512, 1024) == 0); + + printf("Testing read of bad buffer handle\n"); + ret = do_read(fd, 1234, buf, 0, 1024); + assert(ret == -1 && errno == ENOENT); + + printf("Testing write of bad buffer handle\n"); + ret = do_write(fd, 1234, buf, 0, 1024); + assert(ret == -1 && errno == ENOENT); + + close(fd); + + return 0; +} diff --git a/tests/gem_reg_read.c b/tests/gem_reg_read.c new file mode 100644 index 00000000..1d6db1f1 --- /dev/null +++ b/tests/gem_reg_read.c @@ -0,0 +1,98 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#include <stdio.h> +#include <string.h> +#include "i915_drm.h" +#include "drmtest.h" + +struct local_drm_i915_reg_read { + __u64 offset; + __u64 val; /* Return value */ +}; + +#define REG_READ_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x31, struct local_drm_i915_reg_read) + +static void handle_bad(int ret, int lerrno, int expected, const char *desc) +{ + if (ret != 0 && lerrno != expected) { + fprintf(stderr, "%s - errno was %d, but should have been %d\n", + desc, lerrno, expected); + exit(EXIT_FAILURE); + } else if (ret == 0) { + fprintf(stderr, "%s - Command succeeded, but should have failed\n", + desc); + exit(EXIT_FAILURE); + } +} + +static uint64_t timer_query(int fd) +{ + struct local_drm_i915_reg_read read; + int ret; + + read.offset = 0x2358; + ret = drmIoctl(fd, REG_READ_IOCTL, &read); + if (ret) { + perror("positive test case failed: "); + exit(EXIT_FAILURE); + } + + return read.val; +} + +int main(int argc, char *argv[]) +{ + struct local_drm_i915_reg_read read; + int ret, fd; + uint64_t val; + + fd = drm_open_any(); + + read.offset = 0x2358; + ret = drmIoctl(fd, REG_READ_IOCTL, &read); + if (errno == EINVAL) + exit(77); + else if (ret) + exit(EXIT_FAILURE); + + val = timer_query(fd); + sleep(1); + if (timer_query(fd) == val) { + fprintf(stderr, "Timer isn't moving, probably busted\n"); + exit(EXIT_FAILURE); + } + + /* bad reg */ + read.offset = 0x12345678; + ret = drmIoctl(fd, REG_READ_IOCTL, &read); + handle_bad(ret, errno, EINVAL, "bad register"); + + close(fd); + + exit(EXIT_SUCCESS); +} diff --git a/tests/gem_reloc_vs_gpu.c b/tests/gem_reloc_vs_gpu.c new file mode 100644 index 00000000..47681d51 --- /dev/null +++ b/tests/gem_reloc_vs_gpu.c @@ -0,0 +1,206 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +/* + * Testcase: Kernel relocations vs. gpu races + * + */ + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +uint32_t blob[2048*2048]; +#define NUM_TARGET_BOS 16 +drm_intel_bo *pc_target_bo[NUM_TARGET_BOS]; +drm_intel_bo *dummy_bo; +drm_intel_bo *special_bo; +uint32_t devid; +int special_reloc_ofs; +int special_batch_len; + +#define GFX_OP_PIPE_CONTROL ((0x3<<29)|(0x3<<27)|(0x2<<24)|2) +#define PIPE_CONTROL_WRITE_IMMEDIATE (1<<14) +#define PIPE_CONTROL_WRITE_TIMESTAMP (3<<14) +#define PIPE_CONTROL_DEPTH_STALL (1<<13) +#define PIPE_CONTROL_WC_FLUSH (1<<12) +#define PIPE_CONTROL_IS_FLUSH (1<<11) /* MBZ on Ironlake */ +#define PIPE_CONTROL_TC_FLUSH (1<<10) /* GM45+ only */ +#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1<<1) +#define PIPE_CONTROL_CS_STALL (1<<20) +#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */ + +static void create_special_bo(void) +{ + uint32_t data[1024]; + int len = 0; + int small_pitch = 64; +#define BATCH(dw) data[len++] = (dw); + + memset(data, 0, 4096); + special_bo = drm_intel_bo_alloc(bufmgr, "special batch", 4096, 4096); + + BATCH(XY_COLOR_BLT_CMD | COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB); + BATCH((3 << 24) | (0xf0 << 16) | small_pitch); + BATCH(0); + BATCH(1 << 16 | 1); + special_reloc_ofs = 4*len; + BATCH(0); + BATCH(0xdeadbeef); + +#define CMD_POLY_STIPPLE_OFFSET 0x7906 + /* batchbuffer end */ + if (IS_GEN5(batch->devid)) { + BATCH(CMD_POLY_STIPPLE_OFFSET << 16); + BATCH(0); + } + assert(len % 2 == 0); + BATCH(MI_NOOP); + BATCH(MI_BATCH_BUFFER_END); + + drm_intel_bo_subdata(special_bo, 0, 4096, data); + special_batch_len = len*4; +} + +static void emit_dummy_load(int pitch) +{ + int i; + uint32_t tile_flags = 0; + + if (IS_965(devid)) { + pitch /= 4; + tile_flags = XY_SRC_COPY_BLT_SRC_TILED | + XY_SRC_COPY_BLT_DST_TILED; + } + + for (i = 0; i < 10; i++) { + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB | + tile_flags); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + pitch); + OUT_BATCH(0 << 16 | 1024); + OUT_BATCH((2048) << 16 | (2048)); + OUT_RELOC_FENCED(dummy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(pitch); + OUT_RELOC_FENCED(dummy_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + if (IS_GEN6(devid) || IS_GEN7(devid)) { + BEGIN_BATCH(3); + OUT_BATCH(XY_SETUP_CLIP_BLT_CMD); + OUT_BATCH(0); + OUT_BATCH(0); + ADVANCE_BATCH(); + } + } + intel_batchbuffer_flush(batch); +} + +#define MAX_BLT_SIZE 128 +int main(int argc, char **argv) +{ + uint32_t tiling_mode = I915_TILING_X; + unsigned long pitch, act_size; + int fd, i, ring; + uint32_t test; + + memset(blob, 'A', sizeof(blob)); + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + /* disable reuse, otherwise the test fails */ + //drm_intel_bufmgr_gem_enable_reuse(bufmgr); + devid = intel_get_drm_devid(fd); + batch = intel_batchbuffer_alloc(bufmgr, devid); + + act_size = 2048; + dummy_bo = drm_intel_bo_alloc_tiled(bufmgr, "tiled dummy_bo", act_size, act_size, + 4, &tiling_mode, &pitch, 0); + + drm_intel_bo_subdata(dummy_bo, 0, act_size*act_size*4, blob); + + create_special_bo(); + + if (intel_gen(devid) >= 6) + ring = I915_EXEC_BLT; + else + ring = 0; + + for (i = 0; i < NUM_TARGET_BOS; i++) { + pc_target_bo[i] = drm_intel_bo_alloc(bufmgr, "special batch", 4096, 4096); + emit_dummy_load(pitch); + assert(pc_target_bo[i]->offset == 0); + drm_intel_bo_emit_reloc(special_bo, special_reloc_ofs, + pc_target_bo[i], + 0, + I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER); + drm_intel_bo_mrb_exec(special_bo, special_batch_len, NULL, + 0, 0, ring); + } + + /* Only check at the end to avoid unnecessary synchronous behaviour. */ + for (i = 0; i < NUM_TARGET_BOS; i++) { + drm_intel_bo_get_subdata(pc_target_bo[i], 0, 4, &test); + if (test != 0xdeadbeef) { + fprintf(stderr, "mismatch in buffer %i: 0x%08x instead of 0xdeadbeef\n", i, test); + exit(1); + } + drm_intel_bo_unreference(pc_target_bo[i]); + } + + drm_intel_gem_bo_map_gtt(dummy_bo); + drm_intel_gem_bo_unmap_gtt(dummy_bo); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_ring_sync_loop.c b/tests/gem_ring_sync_loop.c new file mode 100644 index 00000000..b689bcde --- /dev/null +++ b/tests/gem_ring_sync_loop.c @@ -0,0 +1,139 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> (based on gem_storedw_*.c) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" +#include "i830_reg.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static drm_intel_bo *target_buffer; + +/* + * Testcase: Basic check of ring<->ring sync using a dummy reloc + * + * Extremely efficient at catching missed irqs with semaphores=0 ... + */ + +#define MI_COND_BATCH_BUFFER_END (0x36<<23 | 1) +#define MI_DO_COMPARE (1<<21) + +static void +store_dword_loop(void) +{ + int i; + + srandom(0xdeadbeef); + + for (i = 0; i < 0x100000; i++) { + int ring = random() % 3 + 1; + + if (ring == I915_EXEC_RENDER) { + BEGIN_BATCH(4); + OUT_BATCH(MI_COND_BATCH_BUFFER_END | MI_DO_COMPARE); + OUT_BATCH(0xffffffff); /* compare dword */ + OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(MI_NOOP); + ADVANCE_BATCH(); + } else { + BEGIN_BATCH(4); + OUT_BATCH(MI_FLUSH_DW | 1); + OUT_BATCH(0); /* reserved */ + OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(MI_NOOP | (1<<22) | (0xf)); + ADVANCE_BATCH(); + } + intel_batchbuffer_flush_on_ring(batch, ring); + } + + drm_intel_bo_map(target_buffer, 0); + // map to force waiting on rendering + drm_intel_bo_unmap(target_buffer); +} + +int main(int argc, char **argv) +{ + int fd; + int devid; + + if (argc != 1) { + fprintf(stderr, "usage: %s\n", argv[0]); + exit(-1); + } + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + if (!HAS_BLT_RING(devid)) { + fprintf(stderr, "inter ring check needs gen6+\n"); + return 77; + } + + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + if (!bufmgr) { + fprintf(stderr, "failed to init libdrm\n"); + exit(-1); + } + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, devid); + if (!batch) { + fprintf(stderr, "failed to create batch buffer\n"); + exit(-1); + } + + target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096); + if (!target_buffer) { + fprintf(stderr, "failed to alloc target buffer\n"); + exit(-1); + } + + store_dword_loop(); + + drm_intel_bo_unreference(target_buffer); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_ringfill.c b/tests/gem_ringfill.c new file mode 100644 index 00000000..5bae8f11 --- /dev/null +++ b/tests/gem_ringfill.c @@ -0,0 +1,233 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** @file gem_ringfill.c + * + * This is a test of doing many tiny batchbuffer operations, in the hope of + * catching failure to manage the ring properly near full. + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include "drm.h" +#include "i915_drm.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" +#include "rendercopy.h" + +struct bo { + const char *ring; + drm_intel_bo *src, *dst, *tmp; +}; + +static const int width = 512, height = 512; + +static void create_bo(drm_intel_bufmgr *bufmgr, + struct bo *b, + const char *ring) +{ + int size = 4 * width * height, i; + uint32_t *map; + + b->ring = ring; + b->src = drm_intel_bo_alloc(bufmgr, "src", size, 4096); + b->dst = drm_intel_bo_alloc(bufmgr, "dst", size, 4096); + b->tmp = drm_intel_bo_alloc(bufmgr, "tmp", size, 4096); + + /* Fill the src with indexes of the pixels */ + drm_intel_bo_map(b->src, true); + map = b->src->virtual; + for (i = 0; i < width * height; i++) + map[i] = i; + drm_intel_bo_unmap(b->src); + + /* Fill the dst with garbage. */ + drm_intel_bo_map(b->dst, true); + map = b->dst->virtual; + for (i = 0; i < width * height; i++) + map[i] = 0xd0d0d0d0; + drm_intel_bo_unmap(b->dst); +} + +static int check_bo(struct bo *b) +{ + const uint32_t *map; + int i, fails = 0; + + drm_intel_bo_map(b->dst, false); + map = b->dst->virtual; + for (i = 0; i < width*height; i++) { + if (map[i] != i && ++fails <= 9) { + int x = i % width; + int y = i / width; + + printf("%s: copy #%d at %d,%d failed: read 0x%08x\n", + b->ring, i, x, y, map[i]); + } + } + drm_intel_bo_unmap(b->dst); + + return fails; +} + +static void destroy_bo(struct bo *b) +{ + drm_intel_bo_unreference(b->src); + drm_intel_bo_unreference(b->tmp); + drm_intel_bo_unreference(b->dst); +} + +static int check_ring(drm_intel_bufmgr *bufmgr, + struct intel_batchbuffer *batch, + const char *ring, + render_copyfunc_t copy) +{ + struct scratch_buf src, tmp, dst; + struct bo bo; + char output[100]; + int i; + + snprintf(output, 100, "filling %s ring: ", ring); + + create_bo(bufmgr, &bo, ring); + + src.stride = 4 * width; + src.tiling = 0; + src.data = src.cpu_mapping = NULL; + src.size = 4 * width * height; + src.num_tiles = 4 * width * height; + dst = tmp = src; + + src.bo = bo.src; + tmp.bo = bo.tmp; + dst.bo = bo.dst; + + /* The ring we've been using is 128k, and each rendering op + * will use at least 8 dwords: + * + * BATCH_START + * BATCH_START offset + * MI_FLUSH + * STORE_DATA_INDEX + * STORE_DATA_INDEX offset + * STORE_DATA_INDEX value + * MI_USER_INTERRUPT + * (padding) + * + * So iterate just a little more than that -- if we don't fill the ring + * doing this, we aren't likely to with this test. + */ + for (i = 0; i < width * height; i++) { + int x = i % width; + int y = i / width; + + drmtest_progress(output, i, width*height); + + assert(y < height); + + /* Dummy load to fill the ring */ + copy(batch, &src, 0, 0, width, height, &tmp, 0, 0); + /* And copy the src into dst, pixel by pixel */ + copy(batch, &src, x, y, 1, 1, &dst, x, y); + } + + /* verify */ + printf("verifying\n"); + i = check_bo(&bo); + destroy_bo(&bo); + + return i; +} + +static void blt_copy(struct intel_batchbuffer *batch, + struct scratch_buf *src, unsigned src_x, unsigned src_y, + unsigned w, unsigned h, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y) +{ + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + dst->stride); + OUT_BATCH((dst_y << 16) | dst_x); /* dst x1,y1 */ + OUT_BATCH(((dst_y + h) << 16) | (dst_x + w)); /* dst x2,y2 */ + OUT_RELOC(dst->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH((src_y << 16) | src_x); /* src x1,y1 */ + OUT_BATCH(src->stride); + OUT_RELOC(src->bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); +} + +int main(int argc, char **argv) +{ + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + render_copyfunc_t copy; + int fd, fails = 0; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + fails += check_ring(bufmgr, batch, "blt", blt_copy); + + /* Strictly only required on architectures with a separate BLT ring, + * but lets stress everybody. + */ + copy = NULL; + if (IS_GEN2(batch->devid)) + copy = gen2_render_copyfunc; + else if (IS_GEN3(batch->devid)) + copy = gen3_render_copyfunc; + else if (IS_GEN6(batch->devid)) + copy = gen6_render_copyfunc; + if (copy) + fails += check_ring(bufmgr, batch, "render", copy); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return fails != 0; +} diff --git a/tests/gem_set_tiling_vs_blt.c b/tests/gem_set_tiling_vs_blt.c new file mode 100644 index 00000000..5fa90d49 --- /dev/null +++ b/tests/gem_set_tiling_vs_blt.c @@ -0,0 +1,269 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +/** @file gem_set_tiling_vs_blt.c + * + * Testcase: Check for proper synchronization of tiling changes vs. tiled gpu + * access + * + * The blitter on gen3 and earlier needs properly set up fences. Which also + * means that for untiled blits we may not set up a fence before that blt has + * finished. + * + * Current kernels have a bug there, but it's pretty hard to hit because you + * need: + * - a blt on an untiled object which is aligned correctly for tiling. + * - a set_tiling to switch that object to tiling + * - another blt without any intervening cpu access that uses this object. + * + * Testcase has been extended to also check tiled->untiled and tiled->tiled + * transitions (i.e. changing stride). + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <stdbool.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +uint32_t devid; + +#define TEST_SIZE (1024*1024) +#define TEST_STRIDE (4*1024) +#define TEST_HEIGHT(stride) (TEST_SIZE/(stride)) +#define TEST_WIDTH(stride) ((stride)/4) + +uint32_t data[TEST_SIZE/4]; + +static void do_test(uint32_t tiling, unsigned stride, + uint32_t tiling_after, unsigned stride_after) +{ + drm_intel_bo *busy_bo, *test_bo, *target_bo; + int i, ret; + uint32_t *ptr; + uint32_t test_bo_handle; + uint32_t blt_stride, blt_bits; + bool tiling_changed = false; + + printf("filling ring .. "); + busy_bo = drm_intel_bo_alloc(bufmgr, "busy bo bo", 16*1024*1024, 4096); + + for (i = 0; i < 250; i++) { + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + 2*1024*4); + OUT_BATCH(0 << 16 | 1024); + OUT_BATCH((2048) << 16 | (2048)); + OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(2*1024*4); + OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + if (IS_GEN6(devid) || IS_GEN7(devid)) { + BEGIN_BATCH(3); + OUT_BATCH(XY_SETUP_CLIP_BLT_CMD); + OUT_BATCH(0); + OUT_BATCH(0); + ADVANCE_BATCH(); + } + } + intel_batchbuffer_flush(batch); + + printf("playing tricks .. "); + /* first allocate the target so it gets out of the way of playing funky + * tricks */ + target_bo = drm_intel_bo_alloc(bufmgr, "target bo", TEST_SIZE, 4096); + + /* allocate buffer with parameters _after_ transition we want to check + * and touch it, so that it's properly aligned in the gtt. */ + test_bo = drm_intel_bo_alloc(bufmgr, "tiled busy bo", TEST_SIZE, 4096); + test_bo_handle = test_bo->handle; + ret = drm_intel_bo_set_tiling(test_bo, &tiling_after, stride_after); + assert(ret == 0); + drm_intel_gem_bo_map_gtt(test_bo); + ptr = test_bo->virtual; + *ptr = 0; + ptr = NULL; + drm_intel_gem_bo_unmap_gtt(test_bo); + + drm_intel_bo_unreference(test_bo); + + test_bo = NULL; + + /* note we need a bo bigger than batches, otherwise the buffer reuse + * trick will fail. */ + test_bo = drm_intel_bo_alloc(bufmgr, "busy bo", TEST_SIZE, 4096); + if (test_bo_handle != test_bo->handle) + fprintf(stderr, "libdrm reuse trick failed\n"); + test_bo_handle = test_bo->handle; + /* ensure we have the right tiling before we start. */ + ret = drm_intel_bo_set_tiling(test_bo, &tiling, stride); + assert(ret == 0); + + if (tiling == I915_TILING_NONE) { + drm_intel_bo_subdata(test_bo, 0, TEST_SIZE, data); + } else { + drm_intel_gem_bo_map_gtt(test_bo); + ptr = test_bo->virtual; + memcpy(ptr, data, TEST_SIZE); + ptr = NULL; + drm_intel_gem_bo_unmap_gtt(test_bo); + } + + blt_stride = stride; + blt_bits = 0; + if (intel_gen(devid) >= 4 && tiling != I915_TILING_NONE) { + blt_stride /= 4; + blt_bits = XY_SRC_COPY_BLT_SRC_TILED; + } + + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + blt_bits | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + stride); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH((TEST_HEIGHT(stride)) << 16 | (TEST_WIDTH(stride))); + OUT_RELOC_FENCED(target_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(blt_stride); + OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + intel_batchbuffer_flush(batch); + + drm_intel_bo_unreference(test_bo); + + test_bo = drm_intel_bo_alloc_for_render(bufmgr, "tiled busy bo", TEST_SIZE, 4096); + if (test_bo_handle != test_bo->handle) + fprintf(stderr, "libdrm reuse trick failed\n"); + ret = drm_intel_bo_set_tiling(test_bo, &tiling_after, stride_after); + assert(ret == 0); + + /* Note: We don't care about gen4+ here because the blitter doesn't use + * fences there. So not setting tiling flags on the tiled buffer is ok. + */ + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + stride_after); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH((1) << 16 | (1)); + OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(stride_after); + OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + intel_batchbuffer_flush(batch); + + /* Now try to trick the kernel the kernel into changing up the fencing + * too early. */ + + printf("checking .. "); + memset(data, 0, TEST_SIZE); + drm_intel_bo_get_subdata(target_bo, 0, TEST_SIZE, data); + for (i = 0; i < TEST_SIZE/4; i++) + assert(data[i] == i); + + /* check whether tiling on the test_bo actually changed. */ + drm_intel_gem_bo_map_gtt(test_bo); + ptr = test_bo->virtual; + for (i = 0; i < TEST_SIZE/4; i++) + if (ptr[i] != data[i]) + tiling_changed = true; + ptr = NULL; + drm_intel_gem_bo_unmap_gtt(test_bo); + assert(tiling_changed); + + drm_intel_bo_unreference(test_bo); + drm_intel_bo_unreference(target_bo); + drm_intel_bo_unreference(busy_bo); + printf("done\n"); +} + +int main(int argc, char **argv) +{ + int i, fd; + uint32_t tiling, tiling_after; + + for (i = 0; i < 1024*256; i++) + data[i] = i; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + devid = intel_get_drm_devid(fd); + batch = intel_batchbuffer_alloc(bufmgr, devid); + + + printf("testing untiled->tiled transisition:\n"); + tiling = I915_TILING_NONE; + tiling_after = I915_TILING_X; + do_test(tiling, TEST_STRIDE, tiling_after, TEST_STRIDE); + assert(tiling == I915_TILING_NONE); + assert(tiling_after == I915_TILING_X); + + printf("testing tiled->untiled transisition:\n"); + tiling = I915_TILING_X; + tiling_after = I915_TILING_NONE; + do_test(tiling, TEST_STRIDE, tiling_after, TEST_STRIDE); + assert(tiling == I915_TILING_X); + assert(tiling_after == I915_TILING_NONE); + + printf("testing tiled->tiled transisition:\n"); + tiling = I915_TILING_X; + tiling_after = I915_TILING_X; + do_test(tiling, TEST_STRIDE/2, tiling_after, TEST_STRIDE); + assert(tiling == I915_TILING_X); + assert(tiling_after == I915_TILING_X); + + return 0; +} diff --git a/tests/gem_set_tiling_vs_gtt.c b/tests/gem_set_tiling_vs_gtt.c new file mode 100644 index 00000000..1241b54d --- /dev/null +++ b/tests/gem_set_tiling_vs_gtt.c @@ -0,0 +1,137 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#define OBJECT_SIZE (1024*1024) +#define TEST_STRIDE (1024*4) + +/** + * Testcase: Check set_tiling vs gtt mmap coherency + */ + +int main(int argc, char **argv) +{ + int fd; + uint32_t *ptr; + uint32_t data[OBJECT_SIZE/4]; + int i; + uint32_t handle; + bool tiling_changed; + int tile_height; + + fd = drm_open_any(); + + if (IS_GEN2(intel_get_drm_devid(fd))) + tile_height = 16; + else + tile_height = 8; + + handle = gem_create(fd, OBJECT_SIZE); + ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE); + assert(ptr); + + /* gtt coherency is done with set_domain in libdrm, don't break that */ + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + for (i = 0; i < OBJECT_SIZE/4; i++) + ptr[i] = data[i] = i; + + gem_set_tiling(fd, handle, I915_TILING_X, TEST_STRIDE); + + printf("testing untiled->tiled\n"); + tiling_changed = false; + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0); + /* Too lazy to check for the correct tiling, and impossible anyway on + * bit17 swizzling machines. */ + for (i = 0; i < OBJECT_SIZE/4; i++) + if (ptr[i] != data[i]) + tiling_changed = true; + assert(tiling_changed); + + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + for (i = 0; i < OBJECT_SIZE/4; i++) + ptr[i] = data[i] = i; + + gem_set_tiling(fd, handle, I915_TILING_X, TEST_STRIDE*2); + + printf("testing tiled->tiled\n"); + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0); + for (i = 0; i < OBJECT_SIZE/4; i++) { + int tile_row = i / (TEST_STRIDE * tile_height / 4); + int row = i / (TEST_STRIDE * 2 / 4); + int half = i & (TEST_STRIDE / 4); + int ofs = i % (TEST_STRIDE / 4); + int data_i = (tile_row/2)*(TEST_STRIDE * tile_height / 4) + + row*TEST_STRIDE/4 + + half*tile_height + ofs; + uint32_t val = data[data_i]; + + if (ptr[i] != val) { + printf("mismatch at %i, row=%i, half=%i, ofs=%i\n", + i, row, half, ofs); + printf("read: 0x%08x, expected: 0x%08x\n", + ptr[i], val); + assert(0); + } + + } + + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + for (i = 0; i < OBJECT_SIZE/4; i++) + ptr[i] = data[i] = i; + + gem_set_tiling(fd, handle, I915_TILING_NONE, 0); + printf("testing tiled->untiled\n"); + tiling_changed = false; + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0); + /* Too lazy to check for the correct tiling, and impossible anyway on + * bit17 swizzling machines. */ + for (i = 0; i < OBJECT_SIZE/4; i++) + if (ptr[i] != data[i]) + tiling_changed = true; + assert(tiling_changed); + + munmap(ptr, OBJECT_SIZE); + + close(fd); + + return 0; +} diff --git a/tests/gem_set_tiling_vs_pwrite.c b/tests/gem_set_tiling_vs_pwrite.c new file mode 100644 index 00000000..35ec5cdc --- /dev/null +++ b/tests/gem_set_tiling_vs_pwrite.c @@ -0,0 +1,99 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#define OBJECT_SIZE (1024*1024) +#define TEST_STRIDE (1024*4) + +/** + * Testcase: Check set_tiling vs pwrite coherency + */ + +int main(int argc, char **argv) +{ + int fd; + uint32_t *ptr; + uint32_t data[OBJECT_SIZE/4]; + int i; + uint32_t handle; + + fd = drm_open_any(); + + for (i = 0; i < OBJECT_SIZE/4; i++) + data[i] = i; + + handle = gem_create(fd, OBJECT_SIZE); + ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE); + assert(ptr); + + gem_set_tiling(fd, handle, I915_TILING_X, TEST_STRIDE); + + /* touch it */ + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + *ptr = 0xdeadbeef; + + printf("testing pwrite on tiled buffer\n"); + gem_write(fd, handle, 0, data, OBJECT_SIZE); + memset(data, 0, OBJECT_SIZE); + gem_read(fd, handle, 0, data, OBJECT_SIZE); + for (i = 0; i < OBJECT_SIZE/4; i++) + assert(i == data[i]); + + /* touch it before changing the tiling, so that the fence sticks around */ + gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + *ptr = 0xdeadbeef; + + gem_set_tiling(fd, handle, I915_TILING_NONE, 0); + + printf("testing pwrite on untiled, but still fenced buffer\n"); + gem_write(fd, handle, 0, data, OBJECT_SIZE); + memset(data, 0, OBJECT_SIZE); + gem_read(fd, handle, 0, data, OBJECT_SIZE); + for (i = 0; i < OBJECT_SIZE/4; i++) + assert(i == data[i]); + + munmap(ptr, OBJECT_SIZE); + + close(fd); + + return 0; +} diff --git a/tests/gem_storedw_batches_loop.c b/tests/gem_storedw_batches_loop.c new file mode 100644 index 00000000..8cf5f719 --- /dev/null +++ b/tests/gem_storedw_batches_loop.c @@ -0,0 +1,173 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +static drm_intel_bo *target_bo; +static int has_ppgtt = 0; + +/* Like the store dword test, but we create new command buffers each time */ +static void +store_dword_loop(void) +{ + int cmd, i, val = 0, ret; + uint32_t *buf; + drm_intel_bo *cmd_bo; + + cmd = MI_STORE_DWORD_IMM; + if (!has_ppgtt) + cmd |= MI_MEM_VIRTUAL; + + for (i = 0; i < 0x80000; i++) { + cmd_bo = drm_intel_bo_alloc(bufmgr, "cmd bo", 4096, 4096); + if (!cmd_bo) { + fprintf(stderr, "failed to alloc cmd bo\n"); + exit(-1); + } + + drm_intel_bo_map(cmd_bo, 1); + buf = cmd_bo->virtual; + + buf[0] = cmd; + buf[1] = 0; + buf[2] = target_bo->offset; + buf[3] = 0x42000000 + val; + + ret = drm_intel_bo_references(cmd_bo, target_bo); + if (ret) { + fprintf(stderr, "failed to link cmd & target bos\n"); + exit(-1); + } + + ret = drm_intel_bo_emit_reloc(cmd_bo, 8, target_bo, 0, + I915_GEM_DOMAIN_INSTRUCTION, + I915_GEM_DOMAIN_INSTRUCTION); + if (ret) { + fprintf(stderr, "failed to emit reloc\n"); + exit(-1); + } + + buf[4] = MI_BATCH_BUFFER_END; + buf[5] = MI_BATCH_BUFFER_END; + + drm_intel_bo_unmap(cmd_bo); + + ret = drm_intel_bo_references(cmd_bo, target_bo); + if (ret != 1) { + fprintf(stderr, "bad bo reference count: %d\n", ret); + exit(-1); + } + + ret = drm_intel_bo_exec(cmd_bo, 6 * 4, NULL, 0, 0); + if (ret) { + fprintf(stderr, "bo exec failed: %d\n", ret); + exit(-1); + } + + drm_intel_bo_wait_rendering(cmd_bo); + + drm_intel_bo_map(target_bo, 1); + + buf = target_bo->virtual; + if (buf[0] != (0x42000000 | val)) { + fprintf(stderr, + "value mismatch: cur 0x%08x, stored 0x%08x\n", + buf[0], 0x42000000 | val); + exit(-1); + } + buf[0] = 0; /* let batch write it again */ + drm_intel_bo_unmap(target_bo); + + drm_intel_bo_unreference(cmd_bo); + + val++; + } + + printf("completed %d writes successfully\n", i); +} + +int main(int argc, char **argv) +{ + int fd; + int devid; + + if (argc != 1) { + fprintf(stderr, "usage: %s\n", argv[0]); + exit(-1); + } + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + + has_ppgtt = gem_uses_aliasing_ppgtt(fd); + + if (IS_GEN2(devid) || IS_GEN3(devid) || IS_GEN4(devid) || IS_GEN5(devid)) { + + fprintf(stderr, "MI_STORE_DATA can only use GTT address on gen4+/g33 and" + "needs snoopable mem on pre-gen6\n"); + return 77; + } + + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + if (!bufmgr) { + fprintf(stderr, "failed to init libdrm\n"); + exit(-1); + } +// drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + target_bo = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096); + if (!target_bo) { + fprintf(stderr, "failed to alloc target buffer\n"); + exit(-1); + } + + store_dword_loop(); + + drm_intel_bo_unreference(target_bo); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_storedw_loop_blt.c b/tests/gem_storedw_loop_blt.c new file mode 100644 index 00000000..dda9b835 --- /dev/null +++ b/tests/gem_storedw_loop_blt.c @@ -0,0 +1,154 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static drm_intel_bo *target_buffer; +static int has_ppgtt = 0; + +/* + * Testcase: Basic blitter MI check using MI_STORE_DATA_IMM + */ + +static void +store_dword_loop(void) +{ + int cmd, i, val = 0; + uint32_t *buf; + + cmd = MI_STORE_DWORD_IMM; + if (!has_ppgtt) + cmd |= MI_MEM_VIRTUAL; + + for (i = 0; i < 0x100000; i++) { + BEGIN_BATCH(4); + OUT_BATCH(cmd); + OUT_BATCH(0); /* reserved */ + OUT_RELOC(target_buffer, I915_GEM_DOMAIN_INSTRUCTION, + I915_GEM_DOMAIN_INSTRUCTION, 0); + OUT_BATCH(val); + ADVANCE_BATCH(); + + intel_batchbuffer_flush_on_ring(batch, I915_EXEC_BLT); + + drm_intel_bo_map(target_buffer, 0); + + buf = target_buffer->virtual; + if (buf[0] != val) { + fprintf(stderr, + "value mismatch: cur 0x%08x, stored 0x%08x\n", + buf[0], val); + exit(-1); + } + + drm_intel_bo_unmap(target_buffer); + + val++; + } + + drm_intel_bo_map(target_buffer, 0); + buf = target_buffer->virtual; + + printf("completed %d writes successfully, current value: 0x%08x\n", i, + buf[0]); + drm_intel_bo_unmap(target_buffer); +} + +int main(int argc, char **argv) +{ + int fd; + int devid; + + if (argc != 1) { + fprintf(stderr, "usage: %s\n", argv[0]); + exit(-1); + } + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + + has_ppgtt = gem_uses_aliasing_ppgtt(fd); + + if (IS_GEN2(devid) || IS_GEN3(devid) || IS_GEN4(devid) || IS_GEN5(devid)) { + + fprintf(stderr, "MI_STORE_DATA can only use GTT address on gen4+/g33 and " + "needs snoopable mem on pre-gen6\n"); + return 77; + } + + /* This only works with ppgtt */ + if (!has_ppgtt) { + fprintf(stderr, "no ppgtt detected, which is required\n"); + return 77; + } + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + if (!bufmgr) { + fprintf(stderr, "failed to init libdrm\n"); + exit(-1); + } + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, devid); + if (!batch) { + fprintf(stderr, "failed to create batch buffer\n"); + exit(-1); + } + + target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096); + if (!target_buffer) { + fprintf(stderr, "failed to alloc target buffer\n"); + exit(-1); + } + + store_dword_loop(); + + drm_intel_bo_unreference(target_buffer); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_storedw_loop_bsd.c b/tests/gem_storedw_loop_bsd.c new file mode 100644 index 00000000..d7c61047 --- /dev/null +++ b/tests/gem_storedw_loop_bsd.c @@ -0,0 +1,160 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static drm_intel_bo *target_buffer; +static int has_ppgtt = 0; + +/* + * Testcase: Basic bsd MI check using MI_STORE_DATA_IMM + */ + +static void +store_dword_loop(void) +{ + int cmd, i, val = 0; + uint32_t *buf; + + cmd = MI_STORE_DWORD_IMM; + if (!has_ppgtt) + cmd |= MI_MEM_VIRTUAL; + + for (i = 0; i < 0x100000; i++) { + BEGIN_BATCH(4); + OUT_BATCH(cmd); + OUT_BATCH(0); /* reserved */ + OUT_RELOC(target_buffer, I915_GEM_DOMAIN_INSTRUCTION, + I915_GEM_DOMAIN_INSTRUCTION, 0); + OUT_BATCH(val); + ADVANCE_BATCH(); + + intel_batchbuffer_flush_on_ring(batch, I915_EXEC_BSD); + + drm_intel_bo_map(target_buffer, 0); + + buf = target_buffer->virtual; + if (buf[0] != val) { + fprintf(stderr, + "value mismatch: cur 0x%08x, stored 0x%08x\n", + buf[0], val); + exit(-1); + } + + drm_intel_bo_unmap(target_buffer); + + val++; + } + + drm_intel_bo_map(target_buffer, 0); + buf = target_buffer->virtual; + + printf("completed %d writes successfully, current value: 0x%08x\n", i, + buf[0]); + drm_intel_bo_unmap(target_buffer); +} + +int main(int argc, char **argv) +{ + int fd; + int devid; + + if (argc != 1) { + fprintf(stderr, "usage: %s\n", argv[0]); + exit(-1); + } + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + + has_ppgtt = gem_uses_aliasing_ppgtt(fd); + + if (IS_GEN2(devid) || IS_GEN3(devid) || IS_GEN4(devid) || IS_GEN5(devid)) { + + fprintf(stderr, "MI_STORE_DATA can only use GTT address on gen4+/g33 and " + "needs snoopable mem on pre-gen6\n"); + return 77; + } + + if (IS_GEN6(devid)) { + + fprintf(stderr, "MI_STORE_DATA broken on gen6 bsd\n"); + return 77; + } + + /* This only works with ppgtt */ + if (!has_ppgtt) { + fprintf(stderr, "no ppgtt detected, which is required\n"); + return 77; + } + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + if (!bufmgr) { + fprintf(stderr, "failed to init libdrm\n"); + exit(-1); + } + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, devid); + if (!batch) { + fprintf(stderr, "failed to create batch buffer\n"); + exit(-1); + } + + target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096); + if (!target_buffer) { + fprintf(stderr, "failed to alloc target buffer\n"); + exit(-1); + } + + store_dword_loop(); + + drm_intel_bo_unreference(target_buffer); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_storedw_loop_render.c b/tests/gem_storedw_loop_render.c new file mode 100644 index 00000000..19a41b65 --- /dev/null +++ b/tests/gem_storedw_loop_render.c @@ -0,0 +1,148 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static drm_intel_bo *target_buffer; +static int has_ppgtt = 0; + +/* + * Testcase: Basic render MI check using MI_STORE_DATA_IMM + */ + +static void +store_dword_loop(void) +{ + int cmd, i, val = 0; + uint32_t *buf; + + cmd = MI_STORE_DWORD_IMM; + if (!has_ppgtt) + cmd |= MI_MEM_VIRTUAL; + + for (i = 0; i < 0x100000; i++) { + BEGIN_BATCH(4); + OUT_BATCH(cmd); + OUT_BATCH(0); /* reserved */ + OUT_RELOC(target_buffer, I915_GEM_DOMAIN_INSTRUCTION, + I915_GEM_DOMAIN_INSTRUCTION, 0); + OUT_BATCH(val); + ADVANCE_BATCH(); + + intel_batchbuffer_flush_on_ring(batch, 0); + + drm_intel_bo_map(target_buffer, 0); + + buf = target_buffer->virtual; + if (buf[0] != val) { + fprintf(stderr, + "value mismatch: cur 0x%08x, stored 0x%08x\n", + buf[0], val); + exit(-1); + } + + drm_intel_bo_unmap(target_buffer); + + val++; + } + + drm_intel_bo_map(target_buffer, 0); + buf = target_buffer->virtual; + + printf("completed %d writes successfully, current value: 0x%08x\n", i, + buf[0]); + drm_intel_bo_unmap(target_buffer); +} + +int main(int argc, char **argv) +{ + int fd; + int devid; + + if (argc != 1) { + fprintf(stderr, "usage: %s\n", argv[0]); + exit(-1); + } + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + + has_ppgtt = gem_uses_aliasing_ppgtt(fd); + + if (IS_GEN2(devid) || IS_GEN3(devid) || IS_GEN4(devid) || IS_GEN5(devid)) { + + fprintf(stderr, "MI_STORE_DATA can only use GTT address on gen4+/g33 and " + "needs snoopable mem on pre-gen6\n"); + return 77; + } + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + if (!bufmgr) { + fprintf(stderr, "failed to init libdrm\n"); + exit(-1); + } + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, devid); + if (!batch) { + fprintf(stderr, "failed to create batch buffer\n"); + exit(-1); + } + + target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096); + if (!target_buffer) { + fprintf(stderr, "failed to alloc target buffer\n"); + exit(-1); + } + + store_dword_loop(); + + drm_intel_bo_unreference(target_buffer); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_stress.c b/tests/gem_stress.c new file mode 100644 index 00000000..69239ac1 --- /dev/null +++ b/tests/gem_stress.c @@ -0,0 +1,945 @@ +/* + * Copyright © 2011 Daniel Vetter + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + * Partially based upon gem_tiled_fence_blits.c + */ + +/** @file gem_stress.c + * + * This is a general gem coherency test. It's designed to eventually replicate + * any possible sequence of access patterns. It works by copying a set of tiles + * between two sets of backing buffer objects, randomly permutating the assinged + * position on each copy operations. + * + * The copy operation are done in tiny portions (to reduce any race windows + * for corruptions, hence increasing the chances for observing one) and are + * constantly switched between all means to copy stuff (fenced blitter, unfenced + * render, mmap, pwrite/read). + * + * After every complete move of a set tiling parameters of a buffer are randomly + * changed to simulate the effects of libdrm caching. + * + * Buffers are 1mb big to nicely fit into fences on gen2/3. A few are further + * split up to test relaxed fencing. Using this to push the average working set + * size over the available gtt space forces objects to be mapped as unfenceable + * (and as a side-effect tests gtt map/unmap coherency). + * + * In short: designed for maximum evilness. + */ + +#include "rendercopy.h" + +#define CMD_POLY_STIPPLE_OFFSET 0x7906 + +/** TODO: + * - beat on relaxed fencing (i.e. mappable/fenceable tracking in the kernel) + * - render copy (to check fence tracking and cache coherency management by the + * kernel) + * - multi-threading: probably just a wrapper script to launch multiple + * instances + an option to accordingly reduce the working set + * - gen6 inter-ring coherency (needs render copy, first) + * - variable buffer size + * - add an option to fork a second process that randomly sends signals to the + * first one (to check consistency of the kernel recovery paths) + */ + +drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +int drm_fd; +int devid; +int num_fences; + +drm_intel_bo *busy_bo; + +struct option_struct { + unsigned scratch_buf_size; + unsigned max_dimension; + unsigned num_buffers; + int trace_tile; + int no_hw; + int gpu_busy_load; + int use_render; + int use_blt; + int forced_tiling; + int use_cpu_maps; + int total_rounds; + int fail; + int tiles_per_buf; + int ducttape; + int tile_size; + int check_render_cpyfn; + int use_signal_helper; +}; + +struct option_struct options; + +#define MAX_BUFS 4096 +#define SCRATCH_BUF_SIZE 1024*1024 +#define BUSY_BUF_SIZE (256*4096) +#define TILE_BYTES(size) ((size)*(size)*sizeof(uint32_t)) + +static struct scratch_buf buffers[2][MAX_BUFS]; +/* tile i is at logical position tile_permutation[i] */ +static unsigned *tile_permutation; +static unsigned num_buffers = 0; +static unsigned current_set = 0; +static unsigned target_set = 0; +static unsigned num_total_tiles = 0; + +int fence_storm = 0; +static int gpu_busy_load = 10; + +struct { + unsigned num_failed; + unsigned max_failed_reads; +} stats; + +static void tile2xy(struct scratch_buf *buf, unsigned tile, unsigned *x, unsigned *y) +{ + assert(tile < buf->num_tiles); + *x = (tile*options.tile_size) % (buf->stride/sizeof(uint32_t)); + *y = ((tile*options.tile_size) / (buf->stride/sizeof(uint32_t))) * options.tile_size; +} + +static void emit_blt(drm_intel_bo *src_bo, uint32_t src_tiling, unsigned src_pitch, + unsigned src_x, unsigned src_y, unsigned w, unsigned h, + drm_intel_bo *dst_bo, uint32_t dst_tiling, unsigned dst_pitch, + unsigned dst_x, unsigned dst_y) +{ + uint32_t cmd_bits = 0; + + if (IS_965(devid) && src_tiling) { + src_pitch /= 4; + cmd_bits |= XY_SRC_COPY_BLT_SRC_TILED; + } + + if (IS_965(devid) && dst_tiling) { + dst_pitch /= 4; + cmd_bits |= XY_SRC_COPY_BLT_DST_TILED; + } + + /* copy lower half to upper half */ + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB | + cmd_bits); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + dst_pitch); + OUT_BATCH(dst_y << 16 | dst_x); + OUT_BATCH((dst_y+h) << 16 | (dst_x+w)); + OUT_RELOC_FENCED(dst_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(src_y << 16 | src_x); + OUT_BATCH(src_pitch); + OUT_RELOC_FENCED(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + if (IS_GEN6(devid) || IS_GEN7(devid)) { + BEGIN_BATCH(3); + OUT_BATCH(XY_SETUP_CLIP_BLT_CMD); + OUT_BATCH(0); + OUT_BATCH(0); + ADVANCE_BATCH(); + } +} + +/* All this gem trashing wastes too much cpu time, so give the gpu something to + * do to increase changes for races. */ +static void keep_gpu_busy(void) +{ + int tmp; + + tmp = 1 << gpu_busy_load; + assert(tmp <= 1024); + + emit_blt(busy_bo, 0, 4096, 0, 0, tmp, 128, + busy_bo, 0, 4096, 0, 128); +} + +static void set_to_cpu_domain(struct scratch_buf *buf, int writing) +{ + gem_set_domain(drm_fd, buf->bo->handle, I915_GEM_DOMAIN_CPU, + writing ? I915_GEM_DOMAIN_CPU : 0); +} + +static unsigned int copyfunc_seq = 0; +static void (*copyfunc)(struct scratch_buf *src, unsigned src_x, unsigned src_y, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y, + unsigned logical_tile_no); + +/* stride, x, y in units of uint32_t! */ +static void cpucpy2d(uint32_t *src, unsigned src_stride, unsigned src_x, unsigned src_y, + uint32_t *dst, unsigned dst_stride, unsigned dst_x, unsigned dst_y, + unsigned logical_tile_no) +{ + int i, j; + int failed = 0; + + for (i = 0; i < options.tile_size; i++) { + for (j = 0; j < options.tile_size; j++) { + unsigned dst_ofs = dst_x + j + dst_stride * (dst_y + i); + unsigned src_ofs = src_x + j + src_stride * (src_y + i); + unsigned expect = logical_tile_no*options.tile_size*options.tile_size + + i*options.tile_size + j; + uint32_t tmp = src[src_ofs]; + if (tmp != expect) { + printf("mismatch at tile %i pos %i, read %i, expected %i, diff %i\n", + logical_tile_no, i*options.tile_size + j, tmp, expect, (int) tmp - expect); + if (options.trace_tile >= 0 && options.fail) + exit(1); + failed++; + } + /* when not aborting, correct any errors */ + dst[dst_ofs] = expect; + } + } + if (failed && options.fail) + exit(1); + + if (failed > stats.max_failed_reads) + stats.max_failed_reads = failed; + if (failed) + stats.num_failed++; +} + +static void cpu_copyfunc(struct scratch_buf *src, unsigned src_x, unsigned src_y, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y, + unsigned logical_tile_no) +{ + assert(batch->ptr == batch->buffer); + + if (options.ducttape) + drm_intel_bo_wait_rendering(dst->bo); + + if (options.use_cpu_maps) { + set_to_cpu_domain(src, 0); + set_to_cpu_domain(dst, 1); + } + + cpucpy2d(src->data, src->stride/sizeof(uint32_t), src_x, src_y, + dst->data, dst->stride/sizeof(uint32_t), dst_x, dst_y, + logical_tile_no); +} + +static void prw_copyfunc(struct scratch_buf *src, unsigned src_x, unsigned src_y, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y, + unsigned logical_tile_no) +{ + uint32_t tmp_tile[options.tile_size*options.tile_size]; + int i; + + assert(batch->ptr == batch->buffer); + + if (options.ducttape) + drm_intel_bo_wait_rendering(dst->bo); + + if (src->tiling == I915_TILING_NONE) { + for (i = 0; i < options.tile_size; i++) { + unsigned ofs = src_x*sizeof(uint32_t) + src->stride*(src_y + i); + drm_intel_bo_get_subdata(src->bo, ofs, + options.tile_size*sizeof(uint32_t), + tmp_tile + options.tile_size*i); + } + } else { + if (options.use_cpu_maps) + set_to_cpu_domain(src, 0); + + cpucpy2d(src->data, src->stride/sizeof(uint32_t), src_x, src_y, + tmp_tile, options.tile_size, 0, 0, logical_tile_no); + } + + if (dst->tiling == I915_TILING_NONE) { + for (i = 0; i < options.tile_size; i++) { + unsigned ofs = dst_x*sizeof(uint32_t) + dst->stride*(dst_y + i); + drm_intel_bo_subdata(dst->bo, ofs, + options.tile_size*sizeof(uint32_t), + tmp_tile + options.tile_size*i); + } + } else { + if (options.use_cpu_maps) + set_to_cpu_domain(dst, 1); + + cpucpy2d(tmp_tile, options.tile_size, 0, 0, + dst->data, dst->stride/sizeof(uint32_t), dst_x, dst_y, + logical_tile_no); + } +} + +static void blitter_copyfunc(struct scratch_buf *src, unsigned src_x, unsigned src_y, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y, + unsigned logical_tile_no) +{ + static unsigned keep_gpu_busy_counter = 0; + + /* check both edges of the fence usage */ + if (keep_gpu_busy_counter & 1 && !fence_storm) + keep_gpu_busy(); + + emit_blt(src->bo, src->tiling, src->stride, src_x, src_y, + options.tile_size, options.tile_size, + dst->bo, dst->tiling, dst->stride, dst_x, dst_y); + + if (!(keep_gpu_busy_counter & 1) && !fence_storm) + keep_gpu_busy(); + + keep_gpu_busy_counter++; + + if (src->tiling) + fence_storm--; + if (dst->tiling) + fence_storm--; + + if (fence_storm <= 1) { + fence_storm = 0; + intel_batchbuffer_flush(batch); + } +} + +static void render_copyfunc(struct scratch_buf *src, unsigned src_x, unsigned src_y, + struct scratch_buf *dst, unsigned dst_x, unsigned dst_y, + unsigned logical_tile_no) +{ + static unsigned keep_gpu_busy_counter = 0; + + /* check both edges of the fence usage */ + if (keep_gpu_busy_counter & 1) + keep_gpu_busy(); + + if (IS_GEN2(devid)) + gen2_render_copyfunc(batch, + src, src_x, src_y, + options.tile_size, options.tile_size, + dst, dst_x, dst_y); + else if (IS_GEN3(devid)) + gen3_render_copyfunc(batch, + src, src_x, src_y, + options.tile_size, options.tile_size, + dst, dst_x, dst_y); + else if (IS_GEN6(devid)) + gen6_render_copyfunc(batch, + src, src_x, src_y, + options.tile_size, options.tile_size, + dst, dst_x, dst_y); + else if (IS_GEN7(devid)) + gen7_render_copyfunc(batch, + src, src_x, src_y, + options.tile_size, options.tile_size, + dst, dst_x, dst_y); + else + blitter_copyfunc(src, src_x, src_y, + dst, dst_x, dst_y, + logical_tile_no); + if (!(keep_gpu_busy_counter & 1)) + keep_gpu_busy(); + + keep_gpu_busy_counter++; + intel_batchbuffer_flush(batch); +} + +static void next_copyfunc(int tile) +{ + if (fence_storm) { + if (tile == options.trace_tile) + printf(" using fence storm\n"); + return; + } + + if (copyfunc_seq % 61 == 0 + && options.forced_tiling != I915_TILING_NONE) { + if (tile == options.trace_tile) + printf(" using fence storm\n"); + fence_storm = num_fences; + copyfunc = blitter_copyfunc; + } else if (copyfunc_seq % 17 == 0) { + if (tile == options.trace_tile) + printf(" using cpu\n"); + copyfunc = cpu_copyfunc; + } else if (copyfunc_seq % 19 == 0) { + if (tile == options.trace_tile) + printf(" using prw\n"); + copyfunc = prw_copyfunc; + } else if (copyfunc_seq % 3 == 0 && options.use_render) { + if (tile == options.trace_tile) + printf(" using render\n"); + copyfunc = render_copyfunc; + } else if (options.use_blt){ + if (tile == options.trace_tile) + printf(" using blitter\n"); + copyfunc = blitter_copyfunc; + } else if (options.use_render){ + if (tile == options.trace_tile) + printf(" using render\n"); + copyfunc = render_copyfunc; + } else { + copyfunc = cpu_copyfunc; + } + + copyfunc_seq++; +} + +static void fan_out(void) +{ + uint32_t tmp_tile[options.tile_size*options.tile_size]; + uint32_t seq = 0; + int i, k; + unsigned tile, buf_idx, x, y; + + for (i = 0; i < num_total_tiles; i++) { + tile = i; + buf_idx = tile / options.tiles_per_buf; + tile %= options.tiles_per_buf; + + tile2xy(&buffers[current_set][buf_idx], tile, &x, &y); + + for (k = 0; k < options.tile_size*options.tile_size; k++) + tmp_tile[k] = seq++; + + if (options.use_cpu_maps) + set_to_cpu_domain(&buffers[current_set][buf_idx], 1); + + cpucpy2d(tmp_tile, options.tile_size, 0, 0, + buffers[current_set][buf_idx].data, + buffers[current_set][buf_idx].stride / sizeof(uint32_t), + x, y, i); + } + + for (i = 0; i < num_total_tiles; i++) + tile_permutation[i] = i; +} + +static void fan_in_and_check(void) +{ + uint32_t tmp_tile[options.tile_size*options.tile_size]; + unsigned tile, buf_idx, x, y; + int i; + for (i = 0; i < num_total_tiles; i++) { + tile = tile_permutation[i]; + buf_idx = tile / options.tiles_per_buf; + tile %= options.tiles_per_buf; + + tile2xy(&buffers[current_set][buf_idx], tile, &x, &y); + + if (options.use_cpu_maps) + set_to_cpu_domain(&buffers[current_set][buf_idx], 0); + + cpucpy2d(buffers[current_set][buf_idx].data, + buffers[current_set][buf_idx].stride / sizeof(uint32_t), + x, y, + tmp_tile, options.tile_size, 0, 0, + i); + } +} + +static void sanitize_stride(struct scratch_buf *buf) +{ + + if (buf_height(buf) > options.max_dimension) + buf->stride = buf->size / options.max_dimension; + + if (buf_height(buf) < options.tile_size) + buf->stride = buf->size / options.tile_size; + + if (buf_width(buf) < options.tile_size) + buf->stride = options.tile_size * sizeof(uint32_t); + + assert(buf->stride <= 8192); + assert(buf_width(buf) <= options.max_dimension); + assert(buf_height(buf) <= options.max_dimension); + + assert(buf_width(buf) >= options.tile_size); + assert(buf_height(buf) >= options.tile_size); + +} + +static void init_buffer(struct scratch_buf *buf, unsigned size) +{ + buf->bo = drm_intel_bo_alloc(bufmgr, "tiled bo", size, 4096); + buf->size = size; + assert(buf->bo); + buf->tiling = I915_TILING_NONE; + buf->stride = 4096; + + sanitize_stride(buf); + + if (options.no_hw) + buf->data = malloc(size); + else { + if (options.use_cpu_maps) + drm_intel_bo_map(buf->bo, 1); + else + drm_intel_gem_bo_map_gtt(buf->bo); + buf->data = buf->bo->virtual; + } + + buf->num_tiles = options.tiles_per_buf; +} + +static void exchange_buf(void *array, unsigned i, unsigned j) +{ + struct scratch_buf *buf_arr, tmp; + buf_arr = array; + + memcpy(&tmp, &buf_arr[i], sizeof(struct scratch_buf)); + memcpy(&buf_arr[i], &buf_arr[j], sizeof(struct scratch_buf)); + memcpy(&buf_arr[j], &tmp, sizeof(struct scratch_buf)); +} + + +static void init_set(unsigned set) +{ + long int r; + int i; + + drmtest_permute_array(buffers[set], num_buffers, exchange_buf); + + if (current_set == 1 && options.gpu_busy_load == 0) { + gpu_busy_load++; + if (gpu_busy_load > 10) + gpu_busy_load = 6; + } + + for (i = 0; i < num_buffers; i++) { + r = random(); + if ((r & 3) != 0) + continue; + r >>= 2; + + if ((r & 3) != 0) + buffers[set][i].tiling = I915_TILING_X; + else + buffers[set][i].tiling = I915_TILING_NONE; + r >>= 2; + if (options.forced_tiling >= 0) + buffers[set][i].tiling = options.forced_tiling; + + if (buffers[set][i].tiling == I915_TILING_NONE) { + /* min 64 byte stride */ + r %= 8; + buffers[set][i].stride = 64 * (1 << r); + } else if (IS_GEN2(devid)) { + /* min 128 byte stride */ + r %= 7; + buffers[set][i].stride = 128 * (1 << r); + } else { + /* min 512 byte stride */ + r %= 5; + buffers[set][i].stride = 512 * (1 << r); + } + + sanitize_stride(&buffers[set][i]); + + gem_set_tiling(drm_fd, buffers[set][i].bo->handle, + buffers[set][i].tiling, + buffers[set][i].stride); + + if (options.trace_tile != -1 && i == options.trace_tile/options.tiles_per_buf) + printf("changing buffer %i containing tile %i: tiling %i, stride %i\n", i, + options.trace_tile, + buffers[set][i].tiling, buffers[set][i].stride); + } +} + +static void exchange_uint(void *array, unsigned i, unsigned j) +{ + unsigned *i_arr = array; + unsigned i_tmp; + + i_tmp = i_arr[i]; + i_arr[i] = i_arr[j]; + i_arr[j] = i_tmp; +} + +static void copy_tiles(unsigned *permutation) +{ + unsigned src_tile, src_buf_idx, src_x, src_y; + unsigned dst_tile, dst_buf_idx, dst_x, dst_y; + struct scratch_buf *src_buf, *dst_buf; + int i, idx; + for (i = 0; i < num_total_tiles; i++) { + /* tile_permutation is independent of current_permutation, so + * abuse it to randomize the order of the src bos */ + idx = tile_permutation[i]; + src_buf_idx = idx / options.tiles_per_buf; + src_tile = idx % options.tiles_per_buf; + src_buf = &buffers[current_set][src_buf_idx]; + + tile2xy(src_buf, src_tile, &src_x, &src_y); + + dst_buf_idx = permutation[idx] / options.tiles_per_buf; + dst_tile = permutation[idx] % options.tiles_per_buf; + dst_buf = &buffers[target_set][dst_buf_idx]; + + tile2xy(dst_buf, dst_tile, &dst_x, &dst_y); + + if (options.trace_tile == i) + printf("copying tile %i from %i (%i, %i) to %i (%i, %i)", i, + tile_permutation[i], src_buf_idx, src_tile, + permutation[idx], dst_buf_idx, dst_tile); + + if (options.no_hw) { + cpucpy2d(src_buf->data, + src_buf->stride / sizeof(uint32_t), + src_x, src_y, + dst_buf->data, + dst_buf->stride / sizeof(uint32_t), + dst_x, dst_y, + i); + } else { + next_copyfunc(i); + + copyfunc(src_buf, src_x, src_y, dst_buf, dst_x, dst_y, + i); + } + } + + intel_batchbuffer_flush(batch); +} + +static int get_num_fences(void) +{ + drm_i915_getparam_t gp; + int ret, val; + + gp.param = I915_PARAM_NUM_FENCES_AVAIL; + gp.value = &val; + ret = drmIoctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + assert (ret == 0); + + printf ("total %d fences\n", val); + assert(val > 4); + + return val - 2; +} + +static void sanitize_tiles_per_buf(void) +{ + if (options.tiles_per_buf > options.scratch_buf_size / TILE_BYTES(options.tile_size)) + options.tiles_per_buf = options.scratch_buf_size / TILE_BYTES(options.tile_size); +} + +static void parse_options(int argc, char **argv) +{ + int c, tmp; + int option_index = 0; + static struct option long_options[] = { + {"no-hw", 0, 0, 'd'}, + {"buf-size", 1, 0, 's'}, + {"gpu-busy-load", 1, 0, 'g'}, + {"no-signals", 0, 0, 'S'}, + {"buffer-count", 1, 0, 'c'}, + {"trace-tile", 1, 0, 't'}, + {"disable-blt", 0, 0, 'b'}, + {"disable-render", 0, 0, 'r'}, + {"untiled", 0, 0, 'u'}, + {"x-tiled", 0, 0, 'x'}, + {"use-cpu-maps", 0, 0, 'm'}, + {"rounds", 1, 0, 'o'}, + {"no-fail", 0, 0, 'f'}, + {"tiles-per-buf", 0, 0, 'p'}, +#define DUCTAPE 0xdead0001 + {"remove-duct-tape", 0, 0, DUCTAPE}, +#define TILESZ 0xdead0002 + {"tile-size", 1, 0, TILESZ}, +#define CHCK_RENDER 0xdead0003 + {"check-render-cpyfn", 0, 0, CHCK_RENDER}, + }; + + options.scratch_buf_size = 256*4096; + options.no_hw = 0; + options.use_signal_helper = 1; + options.gpu_busy_load = 0; + options.num_buffers = 0; + options.trace_tile = -1; + options.use_render = 1; + options.use_blt = 1; + options.forced_tiling = -1; + options.use_cpu_maps = 0; + options.total_rounds = 512; + options.fail = 1; + options.ducttape = 1; + options.tile_size = 16; + options.tiles_per_buf = options.scratch_buf_size / TILE_BYTES(options.tile_size); + options.check_render_cpyfn = 0; + + while((c = getopt_long(argc, argv, "ds:g:c:t:rbuxmo:fp:", + long_options, &option_index)) != -1) { + switch(c) { + case 'd': + options.no_hw = 1; + printf("no-hw debug mode\n"); + break; + case 'S': + options.use_signal_helper = 0; + printf("disabling that pesky nuisance who keeps interrupting us\n"); + break; + case 's': + tmp = atoi(optarg); + if (tmp < options.tile_size*8192) + printf("scratch buffer size needs to be at least %i\n", + options.tile_size*8192); + else if (tmp & (tmp - 1)) { + printf("scratch buffer size needs to be a power-of-two\n"); + } else { + printf("fixed scratch buffer size to %u\n", tmp); + options.scratch_buf_size = tmp; + sanitize_tiles_per_buf(); + } + break; + case 'g': + tmp = atoi(optarg); + if (tmp < 0 || tmp > 10) + printf("gpu busy load needs to be bigger than 0 and smaller than 10\n"); + else { + printf("gpu busy load factor set to %i\n", tmp); + gpu_busy_load = options.gpu_busy_load = tmp; + } + break; + case 'c': + options.num_buffers = atoi(optarg); + printf("buffer count set to %i\n", options.num_buffers); + break; + case 't': + options.trace_tile = atoi(optarg); + printf("tracing tile %i\n", options.trace_tile); + break; + case 'r': + options.use_render = 0; + printf("disabling render copy\n"); + break; + case 'b': + options.use_blt = 0; + printf("disabling blt copy\n"); + break; + case 'u': + options.forced_tiling = I915_TILING_NONE; + printf("disabling tiling\n"); + break; + case 'x': + if (options.use_cpu_maps) { + printf("tiling not possible with cpu maps\n"); + } else { + options.forced_tiling = I915_TILING_X; + printf("using only X-tiling\n"); + } + break; + case 'm': + options.use_cpu_maps = 1; + options.forced_tiling = I915_TILING_NONE; + printf("disabling tiling\n"); + break; + case 'o': + options.total_rounds = atoi(optarg); + printf("total rounds %i\n", options.total_rounds); + break; + case 'f': + options.fail = 0; + printf("not failing when detecting errors\n"); + break; + case 'p': + options.tiles_per_buf = atoi(optarg); + printf("tiles per buffer %i\n", options.tiles_per_buf); + break; + case DUCTAPE: + options.ducttape = 0; + printf("applying duct-tape\n"); + break; + case TILESZ: + options.tile_size = atoi(optarg); + sanitize_tiles_per_buf(); + printf("til size %i\n", options.tile_size); + break; + case CHCK_RENDER: + options.check_render_cpyfn = 1; + printf("checking render copy function\n"); + break; + default: + printf("unkown command options\n"); + break; + } + } + + if (optind < argc) + printf("unkown command options\n"); + + /* actually 32767, according to docs, but that kills our nice pot calculations. */ + options.max_dimension = 16*1024; + if (options.use_render) { + if (IS_GEN2(devid) || IS_GEN3(devid)) + options.max_dimension = 2048; + else + options.max_dimension = 8192; + } + printf("Limiting buffer to %dx%d\n", + options.max_dimension, options.max_dimension); +} + +static void init(void) +{ + int i; + unsigned tmp; + + if (options.num_buffers == 0) { + tmp = gem_aperture_size(drm_fd); + tmp = tmp > 256*(1024*1024) ? 256*(1024*1024) : tmp; + num_buffers = 2 * tmp / options.scratch_buf_size / 3; + num_buffers /= 2; + printf("using %u buffers\n", num_buffers); + } else + num_buffers = options.num_buffers; + + bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + drm_intel_bufmgr_gem_enable_fenced_relocs(bufmgr); + num_fences = get_num_fences(); + batch = intel_batchbuffer_alloc(bufmgr, devid); + + busy_bo = drm_intel_bo_alloc(bufmgr, "tiled bo", BUSY_BUF_SIZE, 4096); + if (options.forced_tiling >= 0) + gem_set_tiling(drm_fd, busy_bo->handle, options.forced_tiling, 4096); + + for (i = 0; i < num_buffers; i++) { + init_buffer(&buffers[0][i], options.scratch_buf_size); + init_buffer(&buffers[1][i], options.scratch_buf_size); + + num_total_tiles += buffers[0][i].num_tiles; + } + current_set = 0; + + /* just in case it helps reproducability */ + srandom(0xdeadbeef); +} + +static void check_render_copyfunc(void) +{ + struct scratch_buf src, dst; + uint32_t *ptr; + int i, j, pass; + + if (!options.check_render_cpyfn) + return; + + init_buffer(&src, options.scratch_buf_size); + init_buffer(&dst, options.scratch_buf_size); + + for (pass = 0; pass < 16; pass++) { + int sx = random() % (buf_width(&src)-options.tile_size); + int sy = random() % (buf_height(&src)-options.tile_size); + int dx = random() % (buf_width(&dst)-options.tile_size); + int dy = random() % (buf_height(&dst)-options.tile_size); + + if (options.use_cpu_maps) + set_to_cpu_domain(&src, 1); + + memset(src.data, 0xff, options.scratch_buf_size); + for (j = 0; j < options.tile_size; j++) { + ptr = (uint32_t*)((char *)src.data + sx*4 + (sy+j) * src.stride); + for (i = 0; i < options.tile_size; i++) + ptr[i] = j * options.tile_size + i; + } + + render_copyfunc(&src, sx, sy, &dst, dx, dy, 0); + + if (options.use_cpu_maps) + set_to_cpu_domain(&dst, 0); + + for (j = 0; j < options.tile_size; j++) { + ptr = (uint32_t*)((char *)dst.data + dx*4 + (dy+j) * dst.stride); + for (i = 0; i < options.tile_size; i++) + if (ptr[i] != j * options.tile_size + i) { + printf("render copyfunc mismatch at (%d, %d): found %d, expected %d\n", + i, j, ptr[i], j*options.tile_size + i); + } + } + } +} + + +int main(int argc, char **argv) +{ + int i, j; + unsigned *current_permutation, *tmp_permutation; + + drm_fd = drm_open_any(); + devid = intel_get_drm_devid(drm_fd); + + parse_options(argc, argv); + + /* start our little helper early before too may allocations occur */ + if (options.use_signal_helper) + drmtest_fork_signal_helper(); + + init(); + + check_render_copyfunc(); + + tile_permutation = malloc(num_total_tiles*sizeof(uint32_t)); + current_permutation = malloc(num_total_tiles*sizeof(uint32_t)); + tmp_permutation = malloc(num_total_tiles*sizeof(uint32_t)); + assert(tile_permutation); + assert(current_permutation); + assert(tmp_permutation); + + fan_out(); + + for (i = 0; i < options.total_rounds; i++) { + printf("round %i\n", i); + if (i % 64 == 63) { + fan_in_and_check(); + printf("everything correct after %i rounds\n", i + 1); + } + + target_set = (current_set + 1) & 1; + init_set(target_set); + + for (j = 0; j < num_total_tiles; j++) + current_permutation[j] = j; + drmtest_permute_array(current_permutation, num_total_tiles, exchange_uint); + + copy_tiles(current_permutation); + + memcpy(tmp_permutation, tile_permutation, sizeof(unsigned)*num_total_tiles); + + /* accumulate the permutations */ + for (j = 0; j < num_total_tiles; j++) + tile_permutation[j] = current_permutation[tmp_permutation[j]]; + + current_set = target_set; + } + + fan_in_and_check(); + + fprintf(stderr, "num failed tiles %u, max incoherent bytes %zd\n", + stats.num_failed, stats.max_failed_reads*sizeof(uint32_t)); + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(drm_fd); + + drmtest_stop_signal_helper(); + + return 0; +} diff --git a/tests/gem_tiled_blits.c b/tests/gem_tiled_blits.c new file mode 100644 index 00000000..86c9a886 --- /dev/null +++ b/tests/gem_tiled_blits.c @@ -0,0 +1,214 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** @file gem_tiled_blits.c + * + * This is a test of doing many tiled blits, with a working set + * larger than the aperture size. + * + * The goal is to catch a couple types of failure; + * - Fence management problems on pre-965. + * - A17 or L-shaped memory tiling workaround problems in acceleration. + * + * The model is to fill a collection of 1MB objects in a way that can't trip + * over A6 swizzling -- upload data to a non-tiled object, blit to the tiled + * object. Then, copy the 1MB objects randomly between each other for a while. + * Finally, download their data through linear objects again and see what + * resulted. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static int width = 512, height = 512; + +static drm_intel_bo * +create_bo(uint32_t start_val) +{ + drm_intel_bo *bo, *linear_bo; + uint32_t *linear; + uint32_t tiling = I915_TILING_X; + int ret, i; + + bo = drm_intel_bo_alloc(bufmgr, "tiled bo", 1024 * 1024, 4096); + ret = drm_intel_bo_set_tiling(bo, &tiling, width * 4); + assert(ret == 0); + assert(tiling == I915_TILING_X); + + linear_bo = drm_intel_bo_alloc(bufmgr, "linear src", 1024 * 1024, 4096); + + /* Fill the BO with dwords starting at start_val */ + drm_intel_bo_map(linear_bo, 1); + linear = linear_bo->virtual; + for (i = 0; i < 1024 * 1024 / 4; i++) + linear[i] = start_val++; + drm_intel_bo_unmap(linear_bo); + + intel_copy_bo (batch, bo, linear_bo, width, height); + + drm_intel_bo_unreference(linear_bo); + + return bo; +} + +static void +check_bo(drm_intel_bo *bo, uint32_t start_val) +{ + drm_intel_bo *linear_bo; + uint32_t *linear; + int i; + + linear_bo = drm_intel_bo_alloc(bufmgr, "linear dst", 1024 * 1024, 4096); + + intel_copy_bo(batch, linear_bo, bo, width, height); + + drm_intel_bo_map(linear_bo, 0); + linear = linear_bo->virtual; + + for (i = 0; i < 1024 * 1024 / 4; i++) { + if (linear[i] != start_val) { + fprintf(stderr, "Expected 0x%08x, found 0x%08x " + "at offset 0x%08x\n", + start_val, linear[i], i * 4); + abort(); + } + start_val++; + } + drm_intel_bo_unmap(linear_bo); + + drm_intel_bo_unreference(linear_bo); +} + +int main(int argc, char **argv) +{ + drm_intel_bo **bo; + uint32_t *bo_start_val; + uint32_t start = 0; + int i, fd, count; + + fd = drm_open_any(); + + count = 0; + if (argc > 1) + count = atoi(argv[1]); + if (count == 0) { + count = 3 * gem_aperture_size(fd) / (1024*1024) / 2; + count += (count & 1) == 0; + } + + if (count > intel_get_total_ram_mb() * 9 / 10) { + count = intel_get_total_ram_mb() * 9 / 10; + printf("not enough RAM to run test, reducing buffer count\n"); + } + + printf("Using %d 1MiB buffers\n", count); + + bo = malloc(sizeof(drm_intel_bo *)*count); + bo_start_val = malloc(sizeof(uint32_t)*count); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + for (i = 0; i < count; i++) { + bo[i] = create_bo(start); + bo_start_val[i] = start; + start += 1024 * 1024 / 4; + } + printf("Verifying initialisation...\n"); + for (i = 0; i < count; i++) + check_bo(bo[i], bo_start_val[i]); + + printf("Cyclic blits, forward...\n"); + for (i = 0; i < count * 4; i++) { + int src = i % count; + int dst = (i+1) % count; + + if (src == dst) + continue; + + intel_copy_bo(batch, bo[dst], bo[src], width, height); + bo_start_val[dst] = bo_start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(bo[i], bo_start_val[i]); + + printf("Cyclic blits, backward...\n"); + for (i = 0; i < count * 4; i++) { + int src = (i+1) % count; + int dst = i % count; + + if (src == dst) + continue; + + intel_copy_bo(batch, bo[dst], bo[src], width, height); + bo_start_val[dst] = bo_start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(bo[i], bo_start_val[i]); + + printf("Random blits...\n"); + for (i = 0; i < count * 4; i++) { + int src = random() % count; + int dst = random() % count; + + if (src == dst) + continue; + + intel_copy_bo(batch, bo[dst], bo[src], width, height); + bo_start_val[dst] = bo_start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(bo[i], bo_start_val[i]); + + for (i = 0; i < count; i++) { + drm_intel_bo_unreference(bo[i]); + bo[i] = NULL; + } + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_tiled_fence_blits.c b/tests/gem_tiled_fence_blits.c new file mode 100644 index 00000000..dc654793 --- /dev/null +++ b/tests/gem_tiled_fence_blits.c @@ -0,0 +1,174 @@ +/* + * Copyright © 2009,2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** @file gem_tiled_fence_blits.c + * + * This is a test of doing many tiled blits, with a working set + * larger than the aperture size. + * + * The goal is to catch a couple types of failure; + * - Fence management problems on pre-965. + * - A17 or L-shaped memory tiling workaround problems in acceleration. + * + * The model is to fill a collection of 1MB objects in a way that can't trip + * over A6 swizzling -- upload data to a non-tiled object, blit to the tiled + * object. Then, copy the 1MB objects randomly between each other for a while. + * Finally, download their data through linear objects again and see what + * resulted. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static int width = 512, height = 512; +static uint32_t linear[1024*1024/4]; + +static drm_intel_bo * +create_bo(int fd, uint32_t start_val) +{ + drm_intel_bo *bo; + uint32_t tiling = I915_TILING_X; + int ret, i; + + bo = drm_intel_bo_alloc(bufmgr, "tiled bo", 1024 * 1024, 4096); + ret = drm_intel_bo_set_tiling(bo, &tiling, width * 4); + assert(ret == 0); + assert(tiling == I915_TILING_X); + + /* Fill the BO with dwords starting at start_val */ + for (i = 0; i < 1024 * 1024 / 4; i++) + linear[i] = start_val++; + + gem_write(fd, bo->handle, 0, linear, sizeof(linear)); + + return bo; +} + +static void +check_bo(int fd, drm_intel_bo *bo, uint32_t start_val) +{ + int i; + + gem_read(fd, bo->handle, 0, linear, sizeof(linear)); + + for (i = 0; i < 1024 * 1024 / 4; i++) { + if (linear[i] != start_val) { + fprintf(stderr, "Expected 0x%08x, found 0x%08x " + "at offset 0x%08x\n", + start_val, linear[i], i * 4); + abort(); + } + start_val++; + } +} + +int main(int argc, char **argv) +{ + drm_intel_bo *bo[4096]; + uint32_t bo_start_val[4096]; + uint32_t start = 0; + int fd, i, count; + + fd = drm_open_any(); + count = 3 * gem_aperture_size(fd) / (1024*1024) / 2; + if (count > intel_get_total_ram_mb() * 9 / 10) { + count = intel_get_total_ram_mb() * 9 / 10; + printf("not enough RAM to run test, reducing buffer count\n"); + } + count |= 1; + printf("Using %d 1MiB buffers\n", count); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + for (i = 0; i < count; i++) { + bo[i] = create_bo(fd, start); + bo_start_val[i] = start; + + /* + printf("Creating bo %d\n", i); + check_bo(bo[i], bo_start_val[i]); + */ + + start += 1024 * 1024 / 4; + } + + for (i = 0; i < count; i++) { + int src = count - i - 1; + intel_copy_bo(batch, bo[i], bo[src], width, height); + bo_start_val[i] = bo_start_val[src]; + } + + for (i = 0; i < count * 4; i++) { + int src = random() % count; + int dst = random() % count; + + if (src == dst) + continue; + + intel_copy_bo(batch, bo[dst], bo[src], width, height); + bo_start_val[dst] = bo_start_val[src]; + + /* + check_bo(bo[dst], bo_start_val[dst]); + printf("%d: copy bo %d to %d\n", i, src, dst); + */ + } + + for (i = 0; i < count; i++) { + /* + printf("check %d\n", i); + */ + check_bo(fd, bo[i], bo_start_val[i]); + + drm_intel_bo_unreference(bo[i]); + bo[i] = NULL; + } + + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_tiled_partial_pwrite_pread.c b/tests/gem_tiled_partial_pwrite_pread.c new file mode 100644 index 00000000..bd0d4e09 --- /dev/null +++ b/tests/gem_tiled_partial_pwrite_pread.c @@ -0,0 +1,294 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +/* + * Testcase: pwrite/pread consistency when touching partial cachelines + * + * Some fancy new pwrite/pread optimizations clflush in-line while + * reading/writing. Check whether all required clflushes happen. + * + * Unfortunately really old mesa used unaligned pread/pwrite for s/w fallback + * rendering, so we need to check whether this works on tiled buffers, too. + * + */ + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +drm_intel_bo *scratch_bo; +drm_intel_bo *staging_bo; +drm_intel_bo *tiled_staging_bo; +unsigned long scratch_pitch; +#define BO_SIZE (32*4096) +uint32_t devid; +uint64_t mappable_gtt_limit; +int fd; + +static void +copy_bo(drm_intel_bo *src, int src_tiled, + drm_intel_bo *dst, int dst_tiled) +{ + unsigned long dst_pitch = scratch_pitch; + unsigned long src_pitch = scratch_pitch; + uint32_t cmd_bits = 0; + + /* dst is tiled ... */ + if (intel_gen(devid) >= 4 && dst_tiled) { + dst_pitch /= 4; + cmd_bits |= XY_SRC_COPY_BLT_DST_TILED; + } + + if (intel_gen(devid) >= 4 && dst_tiled) { + src_pitch /= 4; + cmd_bits |= XY_SRC_COPY_BLT_SRC_TILED; + } + + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB | + cmd_bits); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + dst_pitch); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(BO_SIZE/scratch_pitch << 16 | 1024); + OUT_RELOC_FENCED(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(src_pitch); + OUT_RELOC_FENCED(src, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); +} + +static void +blt_bo_fill(drm_intel_bo *tmp_bo, drm_intel_bo *bo, int val) +{ + uint8_t *gtt_ptr; + int i; + + drm_intel_gem_bo_map_gtt(tmp_bo); + gtt_ptr = tmp_bo->virtual; + + for (i = 0; i < BO_SIZE; i++) + gtt_ptr[i] = val; + + drm_intel_gem_bo_unmap_gtt(tmp_bo); + + if (bo->offset < mappable_gtt_limit && + (IS_G33(devid) || intel_gen(devid) >= 4)) + drmtest_trash_aperture(); + + copy_bo(tmp_bo, 0, bo, 1); +} + +#define MAX_BLT_SIZE 128 +#define ROUNDS 200 +int main(int argc, char **argv) +{ + int i, j; + uint8_t tmp[BO_SIZE]; + uint8_t compare_tmp[BO_SIZE]; + uint32_t tiling_mode = I915_TILING_X; + + srandom(0xdeadbeef); + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + //drm_intel_bufmgr_gem_enable_reuse(bufmgr); + devid = intel_get_drm_devid(fd); + batch = intel_batchbuffer_alloc(bufmgr, devid); + + /* overallocate the buffers we're actually using because */ + scratch_bo = drm_intel_bo_alloc_tiled(bufmgr, "scratch bo", 1024, + BO_SIZE/4096, 4, + &tiling_mode, &scratch_pitch, 0); + assert(tiling_mode == I915_TILING_X); + assert(scratch_pitch == 4096); + staging_bo = drm_intel_bo_alloc(bufmgr, "staging bo", BO_SIZE, 4096); + tiled_staging_bo = drm_intel_bo_alloc_tiled(bufmgr, "scratch bo", 1024, + BO_SIZE/4096, 4, + &tiling_mode, + &scratch_pitch, 0); + + drmtest_init_aperture_trashers(bufmgr); + mappable_gtt_limit = gem_mappable_aperture_size(); + + printf("checking partial reads\n"); + for (i = 0; i < ROUNDS; i++) { + int start, len; + int val = i % 256; + + blt_bo_fill(staging_bo, scratch_bo, i); + + start = random() % BO_SIZE; + len = random() % (BO_SIZE-start) + 1; + + drm_intel_bo_get_subdata(scratch_bo, start, len, tmp); + for (j = 0; j < len; j++) { + if (tmp[j] != val) { + printf("mismatch at %i, got: %i, expected: %i\n", + start + j, tmp[j], val); + exit(1); + } + } + + drmtest_progress("partial reads test: ", i, ROUNDS); + } + + printf("checking partial writes\n"); + for (i = 0; i < ROUNDS; i++) { + int start, len; + int val = i % 256; + + blt_bo_fill(staging_bo, scratch_bo, i); + + start = random() % BO_SIZE; + len = random() % (BO_SIZE-start) + 1; + + memset(tmp, i + 63, BO_SIZE); + + drm_intel_bo_subdata(scratch_bo, start, len, tmp); + + copy_bo(scratch_bo, 1, tiled_staging_bo, 1); + drm_intel_bo_get_subdata(tiled_staging_bo, 0, BO_SIZE, + compare_tmp); + + for (j = 0; j < start; j++) { + if (compare_tmp[j] != val) { + printf("amismatch at %i, got: %i, expected: %i\n", + j, tmp[j], val); + exit(1); + } + } + for (; j < start + len; j++) { + if (compare_tmp[j] != tmp[0]) { + printf("bmismatch at %i, got: %i, expected: %i\n", + j, tmp[j], i); + exit(1); + } + } + for (; j < BO_SIZE; j++) { + if (compare_tmp[j] != val) { + printf("cmismatch at %i, got: %i, expected: %i\n", + j, tmp[j], val); + exit(1); + } + } + drm_intel_gem_bo_unmap_gtt(staging_bo); + + drmtest_progress("partial writes test: ", i, ROUNDS); + } + + printf("checking partial writes after partial reads\n"); + for (i = 0; i < ROUNDS; i++) { + int start, len; + int val = i % 256; + + blt_bo_fill(staging_bo, scratch_bo, i); + + /* partial read */ + start = random() % BO_SIZE; + len = random() % (BO_SIZE-start) + 1; + + drm_intel_bo_get_subdata(scratch_bo, start, len, tmp); + for (j = 0; j < len; j++) { + if (tmp[j] != val) { + printf("mismatch in read at %i, got: %i, expected: %i\n", + start + j, tmp[j], val); + exit(1); + } + } + + /* Change contents through gtt to make the pread cachelines + * stale. */ + val = (i + 17) % 256; + blt_bo_fill(staging_bo, scratch_bo, val); + + /* partial write */ + start = random() % BO_SIZE; + len = random() % (BO_SIZE-start) + 1; + + memset(tmp, i + 63, BO_SIZE); + + drm_intel_bo_subdata(scratch_bo, start, len, tmp); + + copy_bo(scratch_bo, 1, tiled_staging_bo, 1); + drm_intel_bo_get_subdata(tiled_staging_bo, 0, BO_SIZE, + compare_tmp); + + for (j = 0; j < start; j++) { + if (compare_tmp[j] != val) { + printf("mismatch at %i, got: %i, expected: %i\n", + j, tmp[j], val); + exit(1); + } + } + for (; j < start + len; j++) { + if (compare_tmp[j] != tmp[0]) { + printf("mismatch at %i, got: %i, expected: %i\n", + j, tmp[j], tmp[0]); + exit(1); + } + } + for (; j < BO_SIZE; j++) { + if (compare_tmp[j] != val) { + printf("mismatch at %i, got: %i, expected: %i\n", + j, tmp[j], val); + exit(1); + } + } + drm_intel_gem_bo_unmap_gtt(staging_bo); + + drmtest_progress("partial read/writes test: ", i, ROUNDS); + } + + drmtest_cleanup_aperture_trashers(); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_tiled_pread.c b/tests/gem_tiled_pread.c new file mode 100644 index 00000000..189affce --- /dev/null +++ b/tests/gem_tiled_pread.c @@ -0,0 +1,237 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** @file gem_tiled_pread.c + * + * This is a test of pread's behavior on tiled objects with respect to the + * reported swizzling value. + * + * The goal is to exercise the slow_bit17_copy path for reading on bit17 + * machines, but will also be useful for catching swizzling value bugs on + * other systems. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#define WIDTH 512 +#define HEIGHT 512 +static uint32_t linear[WIDTH * HEIGHT]; + +#define PAGE_SIZE 4096 + +static int tile_width; +static int tile_height; +static int tile_size; + +static void +gem_get_tiling(int fd, uint32_t handle, uint32_t *tiling, uint32_t *swizzle) +{ + struct drm_i915_gem_get_tiling get_tiling; + int ret; + + memset(&get_tiling, 0, sizeof(get_tiling)); + get_tiling.handle = handle; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling); + assert(ret == 0); + + *tiling = get_tiling.tiling_mode; + *swizzle = get_tiling.swizzle_mode; +} + +static uint32_t +create_bo(int fd) +{ + uint32_t handle; + uint32_t *data; + int i; + + handle = gem_create(fd, sizeof(linear)); + gem_set_tiling(fd, handle, I915_TILING_X, WIDTH * sizeof(uint32_t)); + + /* Fill the BO with dwords starting at start_val */ + data = gem_mmap(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE); + for (i = 0; i < WIDTH*HEIGHT; i++) + data[i] = i; + munmap(data, sizeof(linear)); + + return handle; +} + +static int +swizzle_bit(int bit, int offset) +{ + return (offset & (1 << bit)) >> (bit - 6); +} + +/* Translate from a swizzled offset in the tiled buffer to the corresponding + * value from the original linear buffer. + */ +static uint32_t +calculate_expected(int offset) +{ + int tile_off = offset & (tile_size - 1); + int tile_base = offset & -tile_size; + int tile_index = tile_base / tile_size; + int tiles_per_row = 4*WIDTH / tile_width; + + /* base x,y values from the tile (page) index. */ + int base_y = tile_index / tiles_per_row * tile_height; + int base_x = tile_index % tiles_per_row * (tile_width/4); + + /* x, y offsets within the tile */ + int tile_y = tile_off / tile_width; + int tile_x = (tile_off % tile_width) / 4; + + /* printf("%3d, %3d, %3d,%3d\n", base_x, base_y, tile_x, tile_y); */ + return (base_y + tile_y) * WIDTH + base_x + tile_x; +} + +int +main(int argc, char **argv) +{ + int fd; + int i, iter = 100; + uint32_t tiling, swizzle; + uint32_t handle; + uint32_t devid; + + fd = drm_open_any(); + + handle = create_bo(fd); + gem_get_tiling(fd, handle, &tiling, &swizzle); + + devid = intel_get_drm_devid(fd); + + if (IS_GEN2(devid)) { + tile_height = 16; + tile_width = 128; + tile_size = 2048; + } else { + tile_height = 8; + tile_width = 512; + tile_size = PAGE_SIZE; + } + + /* Read a bunch of random subsets of the data and check that they come + * out right. + */ + for (i = 0; i < iter; i++) { + int size = WIDTH * HEIGHT * 4; + int offset = (random() % size) & ~3; + int len = (random() % size) & ~3; + int j; + + if (len == 0) + len = 4; + + if (offset + len > size) + len = size - offset; + + if (i == 0) { + offset = 0; + len = size; + } + + gem_read(fd, handle, offset, linear, len); + + /* Translate from offsets in the read buffer to the swizzled + * address that it corresponds to. This is the opposite of + * what Mesa does (calculate offset to be read given the linear + * offset it's looking for). + */ + for (j = offset; j < offset + len; j += 4) { + uint32_t expected_val, found_val; + int swizzled_offset; + const char *swizzle_str; + + switch (swizzle) { + case I915_BIT_6_SWIZZLE_NONE: + swizzled_offset = j; + swizzle_str = "none"; + break; + case I915_BIT_6_SWIZZLE_9: + swizzled_offset = j ^ + swizzle_bit(9, j); + swizzle_str = "bit9"; + break; + case I915_BIT_6_SWIZZLE_9_10: + swizzled_offset = j ^ + swizzle_bit(9, j) ^ + swizzle_bit(10, j); + swizzle_str = "bit9^10"; + break; + case I915_BIT_6_SWIZZLE_9_11: + swizzled_offset = j ^ + swizzle_bit(9, j) ^ + swizzle_bit(11, j); + swizzle_str = "bit9^11"; + break; + case I915_BIT_6_SWIZZLE_9_10_11: + swizzled_offset = j ^ + swizzle_bit(9, j) ^ + swizzle_bit(10, j) ^ + swizzle_bit(11, j); + swizzle_str = "bit9^10^11"; + break; + default: + fprintf(stderr, "Bad swizzle bits; %d\n", + swizzle); + abort(); + } + expected_val = calculate_expected(swizzled_offset); + found_val = linear[(j - offset) / 4]; + if (expected_val != found_val) { + fprintf(stderr, + "Bad read [%d]: %d instead of %d at 0x%08x " + "for read from 0x%08x to 0x%08x, swizzle=%s\n", + i, found_val, expected_val, j, + offset, offset + len, + swizzle_str); + abort(); + } + } + } + + close(fd); + + return 0; +} diff --git a/tests/gem_tiled_pread_pwrite.c b/tests/gem_tiled_pread_pwrite.c new file mode 100644 index 00000000..e2225c5e --- /dev/null +++ b/tests/gem_tiled_pread_pwrite.c @@ -0,0 +1,159 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** @file gem_tiled_pread_pwrite.c + * + * This is a test of pread's behavior on tiled objects with respect to the + * reported swizzling value. + * + * The goal is to exercise the slow_bit17_copy path for reading on bit17 + * machines, but will also be useful for catching swizzling value bugs on + * other systems. + */ + +/* + * Testcase: Test swizzling by testing pwrite does the invers of pread + * + * Together with the explicit pread testcase, this should cover our swizzle + * handling. + * + * Note that this test will use swap in an effort to test all of ram. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#define WIDTH 512 +#define HEIGHT 512 +static uint32_t linear[WIDTH * HEIGHT]; +static uint32_t current_tiling_mode; + +#define PAGE_SIZE 4096 + +static void +gem_get_tiling(int fd, uint32_t handle, uint32_t *tiling, uint32_t *swizzle) +{ + struct drm_i915_gem_get_tiling get_tiling; + int ret; + + memset(&get_tiling, 0, sizeof(get_tiling)); + get_tiling.handle = handle; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling); + assert(ret == 0); + + *tiling = get_tiling.tiling_mode; + *swizzle = get_tiling.swizzle_mode; +} + +static uint32_t +create_bo_and_fill(int fd) +{ + uint32_t handle; + uint32_t *data; + int i; + + handle = gem_create(fd, sizeof(linear)); + gem_set_tiling(fd, handle, current_tiling_mode, WIDTH * sizeof(uint32_t)); + + /* Fill the BO with dwords starting at start_val */ + data = gem_mmap(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE); + for (i = 0; i < WIDTH*HEIGHT; i++) + data[i] = i; + munmap(data, sizeof(linear)); + + return handle; +} + +static uint32_t +create_bo(int fd) +{ + uint32_t handle; + + handle = gem_create(fd, sizeof(linear)); + gem_set_tiling(fd, handle, current_tiling_mode, WIDTH * sizeof(uint32_t)); + + return handle; +} + +int +main(int argc, char **argv) +{ + int fd; + uint32_t *data; + int i, j; + uint32_t tiling, swizzle; + uint32_t handle, handle_target; + int count; + + + fd = drm_open_any(); + count = intel_get_total_ram_mb() * 9 / 10; + + for (i = 0; i < count/2; i++) { + current_tiling_mode = I915_TILING_X; + + handle = create_bo_and_fill(fd); + gem_get_tiling(fd, handle, &tiling, &swizzle); + + gem_read(fd, handle, 0, linear, sizeof(linear)); + + handle_target = create_bo(fd); + gem_write(fd, handle_target, 0, linear, sizeof(linear)); + + /* Check the target bo's contents. */ + data = gem_mmap(fd, handle_target, sizeof(linear), PROT_READ | PROT_WRITE); + for (j = 0; j < WIDTH*HEIGHT; j++) + if (data[j] != j) { + fprintf(stderr, "mismatch at %i: %i\n", + j, data[j]); + exit(1); + } + munmap(data, sizeof(linear)); + + /* Leak both bos so that we use all of system mem! */ + + drmtest_progress("gem_tiled_pread_pwrite: ", i, count/2); + } + + close(fd); + + return 0; +} diff --git a/tests/gem_tiled_swapping.c b/tests/gem_tiled_swapping.c new file mode 100644 index 00000000..d1484f0e --- /dev/null +++ b/tests/gem_tiled_swapping.c @@ -0,0 +1,145 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +/** @file gem_tiled_pread_pwrite.c + * + * This is a test of pread's behavior on tiled objects with respect to the + * reported swizzling value. + * + * The goal is to exercise the slow_bit17_copy path for reading on bit17 + * machines, but will also be useful for catching swizzling value bugs on + * other systems. + */ + +/* + * Testcase: Exercise swizzle code for swapping + * + * The swizzle checks in the swapin path are at a different place than the ones + * for pread/pwrite, so we need to check them separately. + * + * This test obviously needs swap present (and exits if none is detected). + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#define WIDTH 512 +#define HEIGHT 512 +static uint32_t linear[WIDTH * HEIGHT]; +static uint32_t current_tiling_mode; + +#define PAGE_SIZE 4096 + +static uint32_t +create_bo_and_fill(int fd) +{ + uint32_t handle; + uint32_t *data; + int i; + + handle = gem_create(fd, sizeof(linear)); + gem_set_tiling(fd, handle, current_tiling_mode, WIDTH * sizeof(uint32_t)); + + /* Fill the BO with dwords starting at start_val */ + data = gem_mmap(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE); + for (i = 0; i < WIDTH*HEIGHT; i++) + data[i] = i; + munmap(data, sizeof(linear)); + + return handle; +} + +uint32_t *bo_handles; +int *idx_arr; + +int +main(int argc, char **argv) +{ + int fd; + uint32_t *data; + int i, j; + int count; + current_tiling_mode = I915_TILING_X; + + fd = drm_open_any(); + /* need slightly more than total ram */ + count = intel_get_total_ram_mb() * 11 / 10; + bo_handles = calloc(count, sizeof(uint32_t)); + assert(bo_handles); + + idx_arr = calloc(count, sizeof(int)); + assert(idx_arr); + + if (intel_get_total_swap_mb() == 0) { + printf("no swap detected\n"); + return 77; + } + + if (intel_get_total_ram_mb() / 4 > intel_get_total_swap_mb()) { + printf("not enough swap detected\n"); + return 77; + } + + for (i = 0; i < count; i++) + bo_handles[i] = create_bo_and_fill(fd); + + for (i = 0; i < count; i++) + idx_arr[i] = i; + + drmtest_permute_array(idx_arr, count, + drmtest_exchange_int); + + for (i = 0; i < count/2; i++) { + /* Check the target bo's contents. */ + data = gem_mmap(fd, bo_handles[idx_arr[i]], + sizeof(linear), PROT_READ | PROT_WRITE); + for (j = 0; j < WIDTH*HEIGHT; j++) + if (data[j] != j) { + fprintf(stderr, "mismatch at %i: %i\n", + j, data[j]); + exit(1); + } + munmap(data, sizeof(linear)); + } + + close(fd); + + return 0; +} diff --git a/tests/gem_unfence_active_buffers.c b/tests/gem_unfence_active_buffers.c new file mode 100644 index 00000000..bffc62ea --- /dev/null +++ b/tests/gem_unfence_active_buffers.c @@ -0,0 +1,171 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +/** @file gem_unfence_active_buffers.c + * + * Testcase: Check for use-after free in the fence stealing code + * + * If we're stealing the fence of a active object where the active list is the + * only thing holding a reference, we need to be careful not to access the old + * object we're stealing the fence from after that reference has been dropped by + * retire_requests. + * + * Note that this needs slab poisoning enabled in the kernel to reliably hit the + * problem - the race window is too small. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <stdbool.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +uint32_t devid; + +#define TEST_SIZE (1024*1024) +#define TEST_STRIDE (4*1024) + +uint32_t data[TEST_SIZE/4]; + +int main(int argc, char **argv) +{ + int i, ret, fd, num_fences; + drm_intel_bo *busy_bo, *test_bo; + uint32_t tiling = I915_TILING_X; + + for (i = 0; i < 1024*256; i++) + data[i] = i; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + devid = intel_get_drm_devid(fd); + batch = intel_batchbuffer_alloc(bufmgr, devid); + + printf("filling ring\n"); + busy_bo = drm_intel_bo_alloc(bufmgr, "busy bo bo", 16*1024*1024, 4096); + + for (i = 0; i < 250; i++) { + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + 2*1024*4); + OUT_BATCH(0 << 16 | 1024); + OUT_BATCH((2048) << 16 | (2048)); + OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(2*1024*4); + OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + if (IS_GEN6(devid) || IS_GEN7(devid)) { + BEGIN_BATCH(3); + OUT_BATCH(XY_SETUP_CLIP_BLT_CMD); + OUT_BATCH(0); + OUT_BATCH(0); + ADVANCE_BATCH(); + } + } + intel_batchbuffer_flush(batch); + + num_fences = gem_available_fences(fd); + printf("creating havoc on %i fences\n", num_fences); + + for (i = 0; i < num_fences*2; i++) { + test_bo = drm_intel_bo_alloc(bufmgr, "test_bo", + TEST_SIZE, 4096); + ret = drm_intel_bo_set_tiling(test_bo, &tiling, TEST_STRIDE); + assert(ret == 0); + + drm_intel_bo_disable_reuse(test_bo); + + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + TEST_STRIDE); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH((1) << 16 | (1)); + OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(TEST_STRIDE); + OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + intel_batchbuffer_flush(batch); + printf("test bo offset: %#lx\n", test_bo->offset); + + drm_intel_bo_unreference(test_bo); + } + + /* launch a few batchs to ensure the damaged slab objects get reused. */ + for (i = 0; i < 10; i++) { + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + 2*1024*4); + OUT_BATCH(0 << 16 | 1024); + OUT_BATCH((1) << 16 | (1)); + OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(0 << 16 | 0); + OUT_BATCH(2*1024*4); + OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + if (IS_GEN6(devid) || IS_GEN7(devid)) { + BEGIN_BATCH(3); + OUT_BATCH(XY_SETUP_CLIP_BLT_CMD); + OUT_BATCH(0); + OUT_BATCH(0); + ADVANCE_BATCH(); + } + } + intel_batchbuffer_flush(batch); + + return 0; +} diff --git a/tests/gem_unref_active_buffers.c b/tests/gem_unref_active_buffers.c new file mode 100644 index 00000000..aa29c1de --- /dev/null +++ b/tests/gem_unref_active_buffers.c @@ -0,0 +1,107 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +/* + * Testcase: Unreferencing of active buffers + * + * Execs buffers and immediately unreferences them, hence the kernel active list + * will be the last one to hold a reference on them. Usually libdrm bo caching + * prevents that by keeping another reference. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; +static drm_intel_bo *load_bo; + +int main(int argc, char **argv) +{ + int fd, i; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + if (!bufmgr) { + fprintf(stderr, "failed to init libdrm\n"); + exit(-1); + } + /* don't enable buffer reuse!! */ + //drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + assert(batch); + + /* put some load onto the gpu to keep the light buffers active for long + * enough */ + for (i = 0; i < 1000; i++) { + load_bo = drm_intel_bo_alloc(bufmgr, "target bo", 1024*4096, 4096); + if (!load_bo) { + fprintf(stderr, "failed to alloc target buffer\n"); + exit(-1); + } + + BEGIN_BATCH(8); + OUT_BATCH(XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + 4096); + OUT_BATCH(0); /* dst x1,y1 */ + OUT_BATCH((1024 << 16) | 512); + OUT_RELOC(load_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH((0 << 16) | 512); /* src x1, y1 */ + OUT_BATCH(4096); + OUT_RELOC(load_bo, I915_GEM_DOMAIN_RENDER, 0, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); + + drm_intel_bo_disable_reuse(load_bo); + drm_intel_bo_unreference(load_bo); + } + + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gem_vmap_blits.c b/tests/gem_vmap_blits.c new file mode 100644 index 00000000..b8868214 --- /dev/null +++ b/tests/gem_vmap_blits.c @@ -0,0 +1,355 @@ +/* + * Copyright © 2009,2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** @file gem_vmap_blits.c + * + * This is a test of doing many blits using a mixture of normal system pages + * and uncached linear buffers, with a working set larger than the + * aperture size. + * + * The goal is to simply ensure the basics work. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" +#include "intel_gpu_tools.h" + +#if !defined(I915_PARAM_HAS_VMAP) +#warning No vmap support in drm, skipping +int main(int argc, char **argv) +{ + fprintf(stderr, "No vmap support in drm.\n"); + return 77; +} +#else + +#define WIDTH 512 +#define HEIGHT 512 + +static uint32_t linear[WIDTH*HEIGHT]; + +static uint32_t gem_vmap(int fd, void *ptr, int size, int read_only) +{ + struct drm_i915_gem_vmap vmap; + + vmap.user_ptr = (uintptr_t)ptr; + vmap.user_size = size; + vmap.flags = 0; + if (read_only) + vmap.flags |= I915_VMAP_READ_ONLY; + + if (drmIoctl(fd, DRM_IOCTL_I915_GEM_VMAP, &vmap)) + return 0; + + return vmap.handle; +} + + +static void gem_vmap_sync(int fd, uint32_t handle) +{ + gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU); +} + +static void +gem_read(int fd, uint32_t handle, int offset, int size, void *buf) +{ + struct drm_i915_gem_pread pread; + int ret; + + pread.handle = handle; + pread.offset = offset; + pread.size = size; + pread.data_ptr = (uintptr_t)buf; + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PREAD, &pread); + assert(ret == 0); +} + +static void +copy(int fd, uint32_t dst, uint32_t src) +{ + uint32_t batch[10]; + struct drm_i915_gem_relocation_entry reloc[2]; + struct drm_i915_gem_exec_object2 obj[3]; + struct drm_i915_gem_execbuffer2 exec; + uint32_t handle; + int ret; + + batch[0] = XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB; + batch[1] = (3 << 24) | /* 32 bits */ + (0xcc << 16) | /* copy ROP */ + WIDTH*4; + batch[2] = 0; /* dst x1,y1 */ + batch[3] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */ + batch[4] = 0; /* dst reloc */ + batch[5] = 0; /* src x1,y1 */ + batch[6] = WIDTH*4; + batch[7] = 0; /* src reloc */ + batch[8] = MI_BATCH_BUFFER_END; + batch[9] = MI_NOOP; + + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, sizeof(batch)); + + reloc[0].target_handle = dst; + reloc[0].delta = 0; + reloc[0].offset = 4 * sizeof(batch[0]); + reloc[0].presumed_offset = 0; + reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;; + reloc[0].write_domain = I915_GEM_DOMAIN_RENDER; + + reloc[1].target_handle = src; + reloc[1].delta = 0; + reloc[1].offset = 7 * sizeof(batch[0]); + reloc[1].presumed_offset = 0; + reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;; + reloc[1].write_domain = 0; + + obj[0].handle = dst; + obj[0].relocation_count = 0; + obj[0].relocs_ptr = 0; + obj[0].alignment = 0; + obj[0].offset = 0; + obj[0].flags = 0; + obj[0].rsvd1 = 0; + obj[0].rsvd2 = 0; + + obj[1].handle = src; + obj[1].relocation_count = 0; + obj[1].relocs_ptr = 0; + obj[1].alignment = 0; + obj[1].offset = 0; + obj[1].flags = 0; + obj[1].rsvd1 = 0; + obj[1].rsvd2 = 0; + + obj[2].handle = handle; + obj[2].relocation_count = 2; + obj[2].relocs_ptr = (uintptr_t)reloc; + obj[2].alignment = 0; + obj[2].offset = 0; + obj[2].flags = 0; + obj[2].rsvd1 = obj[2].rsvd2 = 0; + + exec.buffers_ptr = (uintptr_t)obj; + exec.buffer_count = 3; + exec.batch_start_offset = 0; + exec.batch_len = sizeof(batch); + exec.DR1 = exec.DR4 = 0; + exec.num_cliprects = 0; + exec.cliprects_ptr = 0; + exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0; + exec.rsvd1 = exec.rsvd2 = 0; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + while (ret && errno == EBUSY) { + drmCommandNone(fd, DRM_I915_GEM_THROTTLE); + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + } + assert(ret == 0); + + gem_close(fd, handle); +} + +static uint32_t +create_vmap(int fd, uint32_t val, uint32_t *ptr) +{ + uint32_t handle; + int i; + + handle = gem_vmap(fd, ptr, sizeof(linear), 0); + + /* Fill the BO with dwords starting at val */ + for (i = 0; i < WIDTH*HEIGHT; i++) + ptr[i] = val++; + + return handle; +} + +static uint32_t +create_bo(int fd, uint32_t val) +{ + uint32_t handle; + int i; + + handle = gem_create(fd, sizeof(linear)); + + /* Fill the BO with dwords starting at val */ + for (i = 0; i < WIDTH*HEIGHT; i++) + linear[i] = val++; + gem_write(fd, handle, 0, linear, sizeof(linear)); + + return handle; +} + +static void +check_cpu(uint32_t *ptr, uint32_t val) +{ + int i; + + for (i = 0; i < WIDTH*HEIGHT; i++) { + if (ptr[i] != val) { + fprintf(stderr, "Expected 0x%08x, found 0x%08x " + "at offset 0x%08x\n", + val, ptr[i], i * 4); + abort(); + } + val++; + } +} + +static void +check_gpu(int fd, uint32_t handle, uint32_t val) +{ + gem_read(fd, handle, 0, linear, sizeof(linear)); + check_cpu(linear, val); +} + +static int has_vmap(int fd) +{ + drm_i915_getparam_t gp; + int i; + + gp.param = I915_PARAM_HAS_VMAP; + gp.value = &i; + + return drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0 && i > 0; +} + +int main(int argc, char **argv) +{ + uint32_t *memory; + uint32_t *cpu, *cpu_val; + uint32_t *gpu, *gpu_val; + uint32_t start = 0; + int i, fd, count; + + fd = drm_open_any(); + + if (!has_vmap(fd)) { + fprintf(stderr, "No vmap support, ignoring.\n"); + return 77; + } + + count = 0; + if (argc > 1) + count = atoi(argv[1]); + if (count == 0) + count = 3 * gem_aperture_size(fd) / (1024*1024) / 4; + printf("Using 2x%d 1MiB buffers\n", count); + + memory = malloc(count*sizeof(linear)); + if (memory == NULL) { + fprintf(stderr, "Unable to allocate %lld bytes\n", + (long long)count*sizeof(linear)); + return 1; + } + + gpu = malloc(sizeof(uint32_t)*count*4); + gpu_val = gpu + count; + cpu = gpu_val + count; + cpu_val = cpu + count; + + for (i = 0; i < count; i++) { + gpu[i] = create_bo(fd, start); + gpu_val[i] = start; + start += WIDTH*HEIGHT; + } + + for (i = 0; i < count; i++) { + cpu[i] = create_vmap(fd, start, memory+i*WIDTH*HEIGHT); + cpu_val[i] = start; + start += WIDTH*HEIGHT;; + } + + printf("Verifying initialisation...\n"); + for (i = 0; i < count; i++) { + check_gpu(fd, gpu[i], gpu_val[i]); + check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]); + } + + printf("Cyclic blits cpu->gpu, forward...\n"); + for (i = 0; i < count * 4; i++) { + int src = i % count; + int dst = (i + 1) % count; + + copy(fd, gpu[dst], cpu[src]); + gpu_val[dst] = cpu_val[src]; + } + for (i = 0; i < count; i++) + check_gpu(fd, gpu[i], gpu_val[i]); + + printf("Cyclic blits gpu->cpu, backward...\n"); + for (i = 0; i < count * 4; i++) { + int src = (i + 1) % count; + int dst = i % count; + + copy(fd, cpu[dst], gpu[src]); + cpu_val[dst] = gpu_val[src]; + } + for (i = 0; i < count; i++) { + gem_vmap_sync(fd, cpu[i]); + check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]); + } + + printf("Random blits...\n"); + for (i = 0; i < count * 4; i++) { + int src = random() % count; + int dst = random() % count; + + if (random() & 1) { + copy(fd, gpu[dst], cpu[src]); + gpu_val[dst] = cpu_val[src]; + } else { + copy(fd, cpu[dst], gpu[src]); + cpu_val[dst] = gpu_val[src]; + } + } + for (i = 0; i < count; i++) { + check_gpu(fd, gpu[i], gpu_val[i]); + gem_vmap_sync(fd, cpu[i]); + check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]); + } + + return 0; +} + +#endif diff --git a/tests/gem_wait_render_timeout.c b/tests/gem_wait_render_timeout.c new file mode 100644 index 00000000..c321d36c --- /dev/null +++ b/tests/gem_wait_render_timeout.c @@ -0,0 +1,230 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#include <stdio.h> +#include <time.h> +#include "drm.h" +#include "rendercopy.h" + +#define MSEC_PER_SEC 1000L +#define USEC_PER_MSEC 1000L +#define NSEC_PER_USEC 1000L +#define NSEC_PER_MSEC 1000000L +#define USEC_PER_SEC 1000000L +#define NSEC_PER_SEC 1000000000L + +#define ENOUGH_WORK_IN_SECONDS 2 +#define BUF_SIZE (8<<20) +#define BUF_PAGES ((8<<20)>>12) +drm_intel_bo *dst, *dst2; + +/* returns time diff in milliseconds */ +static int64_t +do_time_diff(struct timespec *end, struct timespec *start) +{ + int64_t ret; + ret = (MSEC_PER_SEC * difftime(end->tv_sec, start->tv_sec)) + + ((end->tv_nsec/NSEC_PER_MSEC) - (start->tv_nsec/NSEC_PER_MSEC)); + return ret; +} + +/* to avoid stupid depencies on libdrm, copy&paste */ +struct local_drm_i915_gem_wait { + /** Handle of BO we shall wait on */ + __u32 bo_handle; + __u32 flags; + /** Number of nanoseconds to wait, Returns time remaining. */ + __u64 timeout_ns; +}; + +# define WAIT_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2c, struct local_drm_i915_gem_wait) + +static int +gem_bo_wait_timeout(int fd, uint32_t handle, uint64_t *timeout_ns) +{ + struct local_drm_i915_gem_wait wait; + int ret; + + assert(timeout_ns); + + wait.bo_handle = handle; + wait.timeout_ns = *timeout_ns; + wait.flags = 0; + ret = drmIoctl(fd, WAIT_IOCTL, &wait); + *timeout_ns = wait.timeout_ns; + + return ret ? -errno : 0; +} + +static bool +gem_bo_busy(int fd, uint32_t handle) +{ + struct drm_i915_gem_busy busy; + + busy.handle = handle; + do_or_die(drmIoctl(fd, DRM_IOCTL_I915_GEM_BUSY, &busy)); + + return !!busy.busy; +} + +static void blt_color_fill(struct intel_batchbuffer *batch, + drm_intel_bo *buf, + const unsigned int pages) +{ + const unsigned short height = pages/4; + const unsigned short width = 4096; + BEGIN_BATCH(5); + OUT_BATCH(COLOR_BLT_CMD | + COLOR_BLT_WRITE_ALPHA | + COLOR_BLT_WRITE_RGB); + OUT_BATCH((3 << 24) | /* 32 Bit Color */ + 0xF0 | /* Raster OP copy background register */ + 0); /* Dest pitch is 0 */ + OUT_BATCH(width << 16 | + height); + OUT_RELOC(buf, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); + OUT_BATCH(rand()); /* random pattern */ + ADVANCE_BATCH(); +} + +int main(int argc, char **argv) +{ + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + uint64_t timeout = ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC; + int fd, ret; + const bool do_signals = true; /* signals will seem to make the operation + * use less process CPU time */ + bool done = false; + int i, iter = 1; + + fd = drm_open_any(); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); + + dst = drm_intel_bo_alloc(bufmgr, "dst", BUF_SIZE, 4096); + dst2 = drm_intel_bo_alloc(bufmgr, "dst2", BUF_SIZE, 4096); + + if (gem_bo_wait_timeout(fd, dst->handle, &timeout) == -EINVAL) { + printf("kernel doesn't support wait_timeout, skipping test\n"); + return -77; + } + timeout = ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC; + + /* Figure out a rough number of fills required to consume 1 second of + * GPU work. + */ + do { + struct timespec start, end; + long diff; + +#ifndef CLOCK_MONOTONIC_RAW +#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC +#endif + + assert(clock_gettime(CLOCK_MONOTONIC_RAW, &start) == 0); + for (i = 0; i < iter; i++) + blt_color_fill(batch, dst, BUF_PAGES); + intel_batchbuffer_flush(batch); + drm_intel_bo_wait_rendering(dst); + assert(clock_gettime(CLOCK_MONOTONIC_RAW, &end) == 0); + + diff = do_time_diff(&end, &start); + assert(diff >= 0); + + if ((diff / MSEC_PER_SEC) > ENOUGH_WORK_IN_SECONDS) + done = true; + else + iter <<= 1; + } while (!done && iter < 1000000); + + assert(iter < 1000000); + + printf("%d iters is enough work\n", iter); + gem_quiescent_gpu(fd); + if (do_signals) + drmtest_fork_signal_helper(); + + /* We should be able to do half as much work in the same amount of time, + * but because we might schedule almost twice as much as required, we + * might accidentally time out. Hence add some fudge. */ + for (i = 0; i < iter/3; i++) + blt_color_fill(batch, dst2, BUF_PAGES); + + intel_batchbuffer_flush(batch); + assert(gem_bo_busy(fd, dst2->handle) == true); + + ret = gem_bo_wait_timeout(fd, dst2->handle, &timeout); + if (ret) { + fprintf(stderr, "Timed wait failed %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + assert(gem_bo_busy(fd, dst2->handle) == false); + assert(timeout != 0); + if (timeout == (ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC)) + printf("Buffer was already done!\n"); + else { + printf("Finished with %lu time remaining\n", timeout); + } + + /* check that polling with timeout=0 works. */ + timeout = 0; + assert(gem_bo_wait_timeout(fd, dst2->handle, &timeout) == 0); + assert(timeout == 0); + + /* Now check that we correctly time out, twice the auto-tune load should + * be good enough. */ + timeout = ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC; + for (i = 0; i < iter*2; i++) + blt_color_fill(batch, dst2, BUF_PAGES); + + intel_batchbuffer_flush(batch); + + ret = gem_bo_wait_timeout(fd, dst2->handle, &timeout); + assert(ret == -ETIME); + assert(timeout == 0); + assert(gem_bo_busy(fd, dst2->handle) == true); + + /* check that polling with timeout=0 works. */ + timeout = 0; + assert(gem_bo_wait_timeout(fd, dst2->handle, &timeout) == -ETIME); + assert(timeout == 0); + + + if (do_signals) + drmtest_stop_signal_helper(); + drm_intel_bo_unreference(dst2); + drm_intel_bo_unreference(dst); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + + close(fd); + + return 0; +} diff --git a/tests/gen3_mixed_blits.c b/tests/gen3_mixed_blits.c new file mode 100644 index 00000000..5bb6d868 --- /dev/null +++ b/tests/gen3_mixed_blits.c @@ -0,0 +1,541 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** @file gen3_linear_render_blits.c + * + * This is a test of doing many blits, with a working set + * larger than the aperture size. + * + * The goal is to simply ensure the basics work. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#include "i915_reg.h" +#include "i915_3d.h" + +#define WIDTH (512) +#define HEIGHT (512) + +static inline uint32_t pack_float(float f) +{ + union { + uint32_t dw; + float f; + } u; + u.f = f; + return u.dw; +} + +static uint32_t fill_reloc(struct drm_i915_gem_relocation_entry *reloc, + uint32_t offset, + uint32_t handle, + uint32_t read_domain, + uint32_t write_domain) +{ + reloc->target_handle = handle; + reloc->delta = 0; + reloc->offset = offset * sizeof(uint32_t); + reloc->presumed_offset = 0; + reloc->read_domains = read_domain; + reloc->write_domain = write_domain; + + return reloc->presumed_offset + reloc->delta; +} + +static void +render_copy(int fd, + uint32_t dst, int dst_tiling, + uint32_t src, int src_tiling, + int use_fence) +{ + uint32_t batch[1024], *b = batch; + struct drm_i915_gem_relocation_entry reloc[2], *r = reloc; + struct drm_i915_gem_exec_object2 obj[3]; + struct drm_i915_gem_execbuffer2 exec; + uint32_t handle; + uint32_t tiling_bits; + int ret; + + /* invariant state */ + *b++ = (_3DSTATE_AA_CMD | + AA_LINE_ECAAR_WIDTH_ENABLE | + AA_LINE_ECAAR_WIDTH_1_0 | + AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0); + *b++ = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD | + IAB_MODIFY_ENABLE | + IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) | + IAB_MODIFY_SRC_FACTOR | + (BLENDFACT_ONE << IAB_SRC_FACTOR_SHIFT) | + IAB_MODIFY_DST_FACTOR | + (BLENDFACT_ZERO << IAB_DST_FACTOR_SHIFT)); + *b++ = (_3DSTATE_DFLT_DIFFUSE_CMD); + *b++ = (0); + *b++ = (_3DSTATE_DFLT_SPEC_CMD); + *b++ = (0); + *b++ = (_3DSTATE_DFLT_Z_CMD); + *b++ = (0); + *b++ = (_3DSTATE_COORD_SET_BINDINGS | + CSB_TCB(0, 0) | + CSB_TCB(1, 1) | + CSB_TCB(2, 2) | + CSB_TCB(3, 3) | + CSB_TCB(4, 4) | + CSB_TCB(5, 5) | + CSB_TCB(6, 6) | + CSB_TCB(7, 7)); + *b++ = (_3DSTATE_RASTER_RULES_CMD | + ENABLE_POINT_RASTER_RULE | + OGL_POINT_RASTER_RULE | + ENABLE_LINE_STRIP_PROVOKE_VRTX | + ENABLE_TRI_FAN_PROVOKE_VRTX | + LINE_STRIP_PROVOKE_VRTX(1) | + TRI_FAN_PROVOKE_VRTX(2) | + ENABLE_TEXKILL_3D_4D | + TEXKILL_4D); + *b++ = (_3DSTATE_MODES_4_CMD | + ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) | + ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) | + ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff)); + *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2); + *b++ = (0x00000000); /* Disable texture coordinate wrap-shortest */ + *b++ = ((1 << S4_POINT_WIDTH_SHIFT) | + S4_LINE_WIDTH_ONE | + S4_CULLMODE_NONE | + S4_VFMT_XY); + *b++ = (0x00000000); /* Stencil. */ + *b++ = (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT); + *b++ = (_3DSTATE_SCISSOR_RECT_0_CMD); + *b++ = (0); + *b++ = (0); + *b++ = (_3DSTATE_DEPTH_SUBRECT_DISABLE); + *b++ = (_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */ + *b++ = (0); + *b++ = (_3DSTATE_STIPPLE); + *b++ = (0x00000000); + *b++ = (_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0); + + /* samler state */ + if (use_fence) { + tiling_bits = MS3_USE_FENCE_REGS; + } else { + tiling_bits = 0; + if (src_tiling != I915_TILING_NONE) + tiling_bits = MS3_TILED_SURFACE; + if (src_tiling == I915_TILING_Y) + tiling_bits |= MS3_TILE_WALK; + } + +#define TEX_COUNT 1 + *b++ = (_3DSTATE_MAP_STATE | (3 * TEX_COUNT)); + *b++ = ((1 << TEX_COUNT) - 1); + *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_SAMPLER, 0); b++; + *b++ = (MAPSURF_32BIT | MT_32BIT_ARGB8888 | tiling_bits | + (HEIGHT - 1) << MS3_HEIGHT_SHIFT | + (WIDTH - 1) << MS3_WIDTH_SHIFT); + *b++ = ((WIDTH-1) << MS4_PITCH_SHIFT); + + *b++ = (_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT)); + *b++ = ((1 << TEX_COUNT) - 1); + *b++ = (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT | + FILTER_NEAREST << SS2_MAG_FILTER_SHIFT | + FILTER_NEAREST << SS2_MIN_FILTER_SHIFT); + *b++ = (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT | + TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT | + 0 << SS3_TEXTUREMAP_INDEX_SHIFT); + *b++ = (0x00000000); + + /* render target state */ + if (use_fence) { + tiling_bits = BUF_3D_USE_FENCE; + } else { + tiling_bits = 0; + if (dst_tiling != I915_TILING_NONE) + tiling_bits = BUF_3D_TILED_SURFACE; + if (dst_tiling == I915_TILING_Y) + tiling_bits |= BUF_3D_TILE_WALK_Y; + } + *b++ = (_3DSTATE_BUF_INFO_CMD); + *b++ = (BUF_3D_ID_COLOR_BACK | tiling_bits | WIDTH*4); + *b = fill_reloc(r++, b-batch, dst, + I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); + b++; + + *b++ = (_3DSTATE_DST_BUF_VARS_CMD); + *b++ = (COLR_BUF_ARGB8888 | + DSTORG_HORT_BIAS(0x8) | + DSTORG_VERT_BIAS(0x8)); + + /* draw rect is unconditional */ + *b++ = (_3DSTATE_DRAW_RECT_CMD); + *b++ = (0x00000000); + *b++ = (0x00000000); /* ymin, xmin */ + *b++ = (DRAW_YMAX(HEIGHT - 1) | + DRAW_XMAX(WIDTH - 1)); + /* yorig, xorig (relate to color buffer?) */ + *b++ = (0x00000000); + + /* texfmt */ + *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2); + *b++ = ((4 << S1_VERTEX_WIDTH_SHIFT) | (4 << S1_VERTEX_PITCH_SHIFT)); + *b++ = (~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D)); + *b++ = (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE | + BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT | + BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT | + BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT); + + /* pixel shader */ + *b++ = (_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2)); + /* decl FS_T0 */ + *b++ = (D0_DCL | + REG_TYPE(FS_T0) << D0_TYPE_SHIFT | + REG_NR(FS_T0) << D0_NR_SHIFT | + ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + *b++ = (0); + *b++ = (0); + /* decl FS_S0 */ + *b++ = (D0_DCL | + (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) | + (REG_NR(FS_S0) << D0_NR_SHIFT) | + ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + *b++ = (0); + *b++ = (0); + /* texld(FS_OC, FS_S0, FS_T0 */ + *b++ = (T0_TEXLD | + (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) | + (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) | + (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT)); + *b++ = ((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) | + (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT)); + *b++ = (0); + + *b++ = (PRIM3D_RECTLIST | (3*4 - 1)); + *b++ = pack_float(WIDTH); + *b++ = pack_float(HEIGHT); + *b++ = pack_float(WIDTH); + *b++ = pack_float(HEIGHT); + + *b++ = pack_float(0); + *b++ = pack_float(HEIGHT); + *b++ = pack_float(0); + *b++ = pack_float(HEIGHT); + + *b++ = pack_float(0); + *b++ = pack_float(0); + *b++ = pack_float(0); + *b++ = pack_float(0); + + *b++ = MI_BATCH_BUFFER_END; + if ((b - batch) & 1) + *b++ = 0; + + assert(b - batch <= 1024); + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0])); + + assert(r-reloc == 2); + + tiling_bits = 0; + if (use_fence) + tiling_bits = EXEC_OBJECT_NEEDS_FENCE; + + obj[0].handle = dst; + obj[0].relocation_count = 0; + obj[0].relocs_ptr = 0; + obj[0].alignment = 0; + obj[0].offset = 0; + obj[0].flags = tiling_bits; + obj[0].rsvd1 = 0; + obj[0].rsvd2 = 0; + + obj[1].handle = src; + obj[1].relocation_count = 0; + obj[1].relocs_ptr = 0; + obj[1].alignment = 0; + obj[1].offset = 0; + obj[1].flags = tiling_bits; + obj[1].rsvd1 = 0; + obj[1].rsvd2 = 0; + + obj[2].handle = handle; + obj[2].relocation_count = 2; + obj[2].relocs_ptr = (uintptr_t)reloc; + obj[2].alignment = 0; + obj[2].offset = 0; + obj[2].flags = 0; + obj[2].rsvd1 = obj[2].rsvd2 = 0; + + exec.buffers_ptr = (uintptr_t)obj; + exec.buffer_count = 3; + exec.batch_start_offset = 0; + exec.batch_len = (b-batch)*sizeof(batch[0]); + exec.DR1 = exec.DR4 = 0; + exec.num_cliprects = 0; + exec.cliprects_ptr = 0; + exec.flags = 0; + i915_execbuffer2_set_context_id(exec, 0); + exec.rsvd2 = 0; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + while (ret && errno == EBUSY) { + drmCommandNone(fd, DRM_I915_GEM_THROTTLE); + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + } + assert(ret == 0); + + gem_close(fd, handle); +} + +static void blt_copy(int fd, uint32_t dst, uint32_t src) +{ + uint32_t batch[1024], *b = batch; + struct drm_i915_gem_relocation_entry reloc[2], *r = reloc; + struct drm_i915_gem_exec_object2 obj[3]; + struct drm_i915_gem_execbuffer2 exec; + uint32_t handle; + int ret; + + *b++ = (XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + *b++ = 3 << 24 | 0xcc << 16 | WIDTH * 4; + *b++ = 0; + *b++ = HEIGHT << 16 | WIDTH; + *b = fill_reloc(r++, b-batch, dst, + I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); b++; + *b++ = 0; + *b++ = WIDTH*4; + *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_RENDER, 0); b++; + + *b++ = MI_BATCH_BUFFER_END; + if ((b - batch) & 1) + *b++ = 0; + + assert(b - batch <= 1024); + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0])); + + assert(r-reloc == 2); + + obj[0].handle = dst; + obj[0].relocation_count = 0; + obj[0].relocs_ptr = 0; + obj[0].alignment = 0; + obj[0].offset = 0; + obj[0].flags = EXEC_OBJECT_NEEDS_FENCE; + obj[0].rsvd1 = 0; + obj[0].rsvd2 = 0; + + obj[1].handle = src; + obj[1].relocation_count = 0; + obj[1].relocs_ptr = 0; + obj[1].alignment = 0; + obj[1].offset = 0; + obj[1].flags = EXEC_OBJECT_NEEDS_FENCE; + obj[1].rsvd1 = 0; + obj[1].rsvd2 = 0; + + obj[2].handle = handle; + obj[2].relocation_count = 2; + obj[2].relocs_ptr = (uintptr_t)reloc; + obj[2].alignment = 0; + obj[2].offset = 0; + obj[2].flags = 0; + obj[2].rsvd1 = obj[2].rsvd2 = 0; + + exec.buffers_ptr = (uintptr_t)obj; + exec.buffer_count = 3; + exec.batch_start_offset = 0; + exec.batch_len = (b-batch)*sizeof(batch[0]); + exec.DR1 = exec.DR4 = 0; + exec.num_cliprects = 0; + exec.cliprects_ptr = 0; + exec.flags = 0; + i915_execbuffer2_set_context_id(exec, 0); + exec.rsvd2 = 0; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + while (ret && errno == EBUSY) { + drmCommandNone(fd, DRM_I915_GEM_THROTTLE); + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + } + assert(ret == 0); + + gem_close(fd, handle); +} + + +static void +copy(int fd, + uint32_t dst, int dst_tiling, + uint32_t src, int src_tiling) +{ +retry: + switch (random() % 3) { + case 0: render_copy(fd, dst, dst_tiling, src, src_tiling, 0); break; + case 1: render_copy(fd, dst, dst_tiling, src, src_tiling, 1); break; + case 2: if (dst_tiling == I915_TILING_Y || src_tiling == I915_TILING_Y) + goto retry; + blt_copy(fd, dst, src); + break; + } +} + +static uint32_t +create_bo(int fd, uint32_t val, int tiling) +{ + uint32_t handle; + uint32_t *v; + int i; + + handle = gem_create(fd, WIDTH*HEIGHT*4); + gem_set_tiling(fd, handle, tiling, WIDTH*4); + + /* Fill the BO with dwords starting at val */ + v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ | PROT_WRITE); + assert(v); + for (i = 0; i < WIDTH*HEIGHT; i++) + v[i] = val++; + munmap(v, WIDTH*HEIGHT*4); + + return handle; +} + +static void +check_bo(int fd, uint32_t handle, uint32_t val) +{ + uint32_t *v; + int i; + + v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ); + assert(v); + for (i = 0; i < WIDTH*HEIGHT; i++) { + if (v[i] != val) { + fprintf(stderr, "Expected 0x%08x, found 0x%08x " + "at offset 0x%08x\n", + val, v[i], i * 4); + abort(); + } + val++; + } + munmap(v, WIDTH*HEIGHT*4); +} + +int main(int argc, char **argv) +{ + uint32_t *handle, *tiling, *start_val; + uint32_t start = 0; + int i, fd, count; + + fd = drm_open_any(); + + if (!IS_GEN3(intel_get_drm_devid(fd))) { + printf("gen3-only test, doing nothing\n"); + return 77; + } + + count = 0; + if (argc > 1) + count = atoi(argv[1]); + if (count == 0) + count = 3 * gem_aperture_size(fd) / (1024*1024) / 2; + printf("Using %d 1MiB buffers\n", count); + + handle = malloc(sizeof(uint32_t)*count*3); + tiling = handle + count; + start_val = tiling + count; + + for (i = 0; i < count; i++) { + handle[i] = create_bo(fd, start, tiling[i] = i % 3); + start_val[i] = start; + start += 1024 * 1024 / 4; + } + + printf("Verifying initialisation..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + printf("Cyclic blits, forward..."); fflush(stdout); + for (i = 0; i < count * 32; i++) { + int src = i % count; + int dst = (i + 1) % count; + + copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]); + start_val[dst] = start_val[src]; + } + printf("verifying..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + printf("Cyclic blits, backward..."); fflush(stdout); + for (i = 0; i < count * 32; i++) { + int src = (i + 1) % count; + int dst = i % count; + + copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]); + start_val[dst] = start_val[src]; + } + printf("verifying..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + printf("Random blits..."); fflush(stdout); + for (i = 0; i < count * 32; i++) { + int src = random() % count; + int dst = random() % count; + + while (src == dst) + dst = random() % count; + + copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]); + start_val[dst] = start_val[src]; + } + printf("verifying..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + return 0; +} diff --git a/tests/gen3_render_linear_blits.c b/tests/gen3_render_linear_blits.c new file mode 100644 index 00000000..529e23ff --- /dev/null +++ b/tests/gen3_render_linear_blits.c @@ -0,0 +1,400 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** @file gen3_linear_render_blits.c + * + * This is a test of doing many blits, with a working set + * larger than the aperture size. + * + * The goal is to simply ensure the basics work. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#include "i915_reg.h" +#include "i915_3d.h" + +#define WIDTH 512 +#define HEIGHT 512 + +static uint32_t linear[WIDTH*HEIGHT]; + +static inline uint32_t pack_float(float f) +{ + union { + uint32_t dw; + float f; + } u; + u.f = f; + return u.dw; +} + +static uint32_t fill_reloc(struct drm_i915_gem_relocation_entry *reloc, + uint32_t offset, + uint32_t handle, + uint32_t read_domain, + uint32_t write_domain) +{ + reloc->target_handle = handle; + reloc->delta = 0; + reloc->offset = offset * sizeof(uint32_t); + reloc->presumed_offset = 0; + reloc->read_domains = read_domain; + reloc->write_domain = write_domain; + + return reloc->presumed_offset + reloc->delta; +} + +static void +copy(int fd, uint32_t dst, uint32_t src) +{ + uint32_t batch[1024], *b = batch; + struct drm_i915_gem_relocation_entry reloc[2], *r = reloc; + struct drm_i915_gem_exec_object2 obj[3]; + struct drm_i915_gem_execbuffer2 exec; + uint32_t handle; + int ret; + + /* invariant state */ + *b++ = (_3DSTATE_AA_CMD | + AA_LINE_ECAAR_WIDTH_ENABLE | + AA_LINE_ECAAR_WIDTH_1_0 | + AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0); + *b++ = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD | + IAB_MODIFY_ENABLE | + IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) | + IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE << + IAB_SRC_FACTOR_SHIFT) | + IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO << + IAB_DST_FACTOR_SHIFT)); + *b++ = (_3DSTATE_DFLT_DIFFUSE_CMD); + *b++ = (0); + *b++ = (_3DSTATE_DFLT_SPEC_CMD); + *b++ = (0); + *b++ = (_3DSTATE_DFLT_Z_CMD); + *b++ = (0); + *b++ = (_3DSTATE_COORD_SET_BINDINGS | + CSB_TCB(0, 0) | + CSB_TCB(1, 1) | + CSB_TCB(2, 2) | + CSB_TCB(3, 3) | + CSB_TCB(4, 4) | + CSB_TCB(5, 5) | CSB_TCB(6, 6) | CSB_TCB(7, 7)); + *b++ = (_3DSTATE_RASTER_RULES_CMD | + ENABLE_POINT_RASTER_RULE | + OGL_POINT_RASTER_RULE | + ENABLE_LINE_STRIP_PROVOKE_VRTX | + ENABLE_TRI_FAN_PROVOKE_VRTX | + LINE_STRIP_PROVOKE_VRTX(1) | + TRI_FAN_PROVOKE_VRTX(2) | ENABLE_TEXKILL_3D_4D | TEXKILL_4D); + *b++ = (_3DSTATE_MODES_4_CMD | + ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) | + ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) | + ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff)); + *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2); + *b++ = (0x00000000); /* Disable texture coordinate wrap-shortest */ + *b++ = ((1 << S4_POINT_WIDTH_SHIFT) | + S4_LINE_WIDTH_ONE | + S4_CULLMODE_NONE | + S4_VFMT_XY); + *b++ = (0x00000000); /* Stencil. */ + *b++ = (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT); + *b++ = (_3DSTATE_SCISSOR_RECT_0_CMD); + *b++ = (0); + *b++ = (0); + *b++ = (_3DSTATE_DEPTH_SUBRECT_DISABLE); + *b++ = (_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */ + *b++ = (0); + *b++ = (_3DSTATE_STIPPLE); + *b++ = (0x00000000); + *b++ = (_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0); + + /* samler state */ +#define TEX_COUNT 1 + *b++ = (_3DSTATE_MAP_STATE | (3 * TEX_COUNT)); + *b++ = ((1 << TEX_COUNT) - 1); + *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_SAMPLER, 0); b++; + *b++ = (MAPSURF_32BIT | MT_32BIT_ARGB8888 | + (HEIGHT - 1) << MS3_HEIGHT_SHIFT | + (WIDTH - 1) << MS3_WIDTH_SHIFT); + *b++ = ((WIDTH-1) << MS4_PITCH_SHIFT); + + *b++ = (_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT)); + *b++ = ((1 << TEX_COUNT) - 1); + *b++ = (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT | + FILTER_NEAREST << SS2_MAG_FILTER_SHIFT | + FILTER_NEAREST << SS2_MIN_FILTER_SHIFT); + *b++ = (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT | + TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT | + 0 << SS3_TEXTUREMAP_INDEX_SHIFT); + *b++ = (0x00000000); + + /* render target state */ + *b++ = (_3DSTATE_BUF_INFO_CMD); + *b++ = (BUF_3D_ID_COLOR_BACK | WIDTH*4); + *b = fill_reloc(r++, b-batch, dst, + I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); + b++; + + *b++ = (_3DSTATE_DST_BUF_VARS_CMD); + *b++ = (COLR_BUF_ARGB8888 | + DSTORG_HORT_BIAS(0x8) | + DSTORG_VERT_BIAS(0x8)); + + /* draw rect is unconditional */ + *b++ = (_3DSTATE_DRAW_RECT_CMD); + *b++ = (0x00000000); + *b++ = (0x00000000); /* ymin, xmin */ + *b++ = (DRAW_YMAX(HEIGHT - 1) | + DRAW_XMAX(WIDTH - 1)); + /* yorig, xorig (relate to color buffer?) */ + *b++ = (0x00000000); + + /* texfmt */ + *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2); + *b++ = ((4 << S1_VERTEX_WIDTH_SHIFT) | (4 << S1_VERTEX_PITCH_SHIFT)); + *b++ = (~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D)); + *b++ = (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE | + BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT | + BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT | + BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT); + + /* pixel shader */ + *b++ = (_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2)); + /* decl FS_T0 */ + *b++ = (D0_DCL | + REG_TYPE(FS_T0) << D0_TYPE_SHIFT | + REG_NR(FS_T0) << D0_NR_SHIFT | + ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + *b++ = (0); + *b++ = (0); + /* decl FS_S0 */ + *b++ = (D0_DCL | + (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) | + (REG_NR(FS_S0) << D0_NR_SHIFT) | + ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + *b++ = (0); + *b++ = (0); + /* texld(FS_OC, FS_S0, FS_T0 */ + *b++ = (T0_TEXLD | + (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) | + (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) | + (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT)); + *b++ = ((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) | + (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT)); + *b++ = (0); + + *b++ = (PRIM3D_RECTLIST | (3*4 - 1)); + *b++ = pack_float(WIDTH); + *b++ = pack_float(HEIGHT); + *b++ = pack_float(WIDTH); + *b++ = pack_float(HEIGHT); + + *b++ = pack_float(0); + *b++ = pack_float(HEIGHT); + *b++ = pack_float(0); + *b++ = pack_float(HEIGHT); + + *b++ = pack_float(0); + *b++ = pack_float(0); + *b++ = pack_float(0); + *b++ = pack_float(0); + + *b++ = MI_BATCH_BUFFER_END; + if ((b - batch) & 1) + *b++ = 0; + + assert(b - batch <= 1024); + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0])); + + assert(r-reloc == 2); + + obj[0].handle = dst; + obj[0].relocation_count = 0; + obj[0].relocs_ptr = 0; + obj[0].alignment = 0; + obj[0].offset = 0; + obj[0].flags = 0; + obj[0].rsvd1 = 0; + obj[0].rsvd2 = 0; + + obj[1].handle = src; + obj[1].relocation_count = 0; + obj[1].relocs_ptr = 0; + obj[1].alignment = 0; + obj[1].offset = 0; + obj[1].flags = 0; + obj[1].rsvd1 = 0; + obj[1].rsvd2 = 0; + + obj[2].handle = handle; + obj[2].relocation_count = 2; + obj[2].relocs_ptr = (uintptr_t)reloc; + obj[2].alignment = 0; + obj[2].offset = 0; + obj[2].flags = 0; + obj[2].rsvd1 = obj[2].rsvd2 = 0; + + exec.buffers_ptr = (uintptr_t)obj; + exec.buffer_count = 3; + exec.batch_start_offset = 0; + exec.batch_len = (b-batch)*sizeof(batch[0]); + exec.DR1 = exec.DR4 = 0; + exec.num_cliprects = 0; + exec.cliprects_ptr = 0; + exec.flags = 0; + i915_execbuffer2_set_context_id(exec, 0); + exec.rsvd2 = 0; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + while (ret && errno == EBUSY) { + drmCommandNone(fd, DRM_I915_GEM_THROTTLE); + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + } + assert(ret == 0); + + gem_close(fd, handle); +} + +static uint32_t +create_bo(int fd, uint32_t val) +{ + uint32_t handle; + int i; + + handle = gem_create(fd, sizeof(linear)); + + /* Fill the BO with dwords starting at val */ + for (i = 0; i < WIDTH*HEIGHT; i++) + linear[i] = val++; + gem_write(fd, handle, 0, linear, sizeof(linear)); + + return handle; +} + +static void +check_bo(int fd, uint32_t handle, uint32_t val) +{ + int i; + + gem_read(fd, handle, 0, linear, sizeof(linear)); + for (i = 0; i < WIDTH*HEIGHT; i++) { + if (linear[i] != val) { + fprintf(stderr, "Expected 0x%08x, found 0x%08x " + "at offset 0x%08x\n", + val, linear[i], i * 4); + abort(); + } + val++; + } +} + +int main(int argc, char **argv) +{ + uint32_t *handle, *start_val; + uint32_t start = 0; + int i, fd, count; + + fd = drm_open_any(); + + if (!IS_GEN3(intel_get_drm_devid(fd))) { + printf("gen3-only test, doing nothing\n"); + return 77; + } + + count = 0; + if (argc > 1) + count = atoi(argv[1]); + if (count == 0) + count = 3 * gem_aperture_size(fd) / (1024*1024) / 2; + printf("Using %d 1MiB buffers\n", count); + + handle = malloc(sizeof(uint32_t)*count*2); + start_val = handle + count; + + for (i = 0; i < count; i++) { + handle[i] = create_bo(fd, start); + start_val[i] = start; + start += 1024 * 1024 / 4; + } + + printf("Verifying initialisation...\n"); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + printf("Cyclic blits, forward...\n"); + for (i = 0; i < count * 4; i++) { + int src = i % count; + int dst = (i + 1) % count; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + printf("Cyclic blits, backward...\n"); + for (i = 0; i < count * 4; i++) { + int src = (i + 1) % count; + int dst = i % count; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + printf("Random blits...\n"); + for (i = 0; i < count * 4; i++) { + int src = random() % count; + int dst = random() % count; + + if (src == dst) + continue; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + return 0; +} diff --git a/tests/gen3_render_mixed_blits.c b/tests/gen3_render_mixed_blits.c new file mode 100644 index 00000000..1353b9d7 --- /dev/null +++ b/tests/gen3_render_mixed_blits.c @@ -0,0 +1,429 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** @file gen3_linear_render_blits.c + * + * This is a test of doing many blits, with a working set + * larger than the aperture size. + * + * The goal is to simply ensure the basics work. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#include "i915_reg.h" +#include "i915_3d.h" + +#define WIDTH 512 +#define HEIGHT 512 + +static inline uint32_t pack_float(float f) +{ + union { + uint32_t dw; + float f; + } u; + u.f = f; + return u.dw; +} + +static uint32_t fill_reloc(struct drm_i915_gem_relocation_entry *reloc, + uint32_t offset, + uint32_t handle, + uint32_t read_domain, + uint32_t write_domain) +{ + reloc->target_handle = handle; + reloc->delta = 0; + reloc->offset = offset * sizeof(uint32_t); + reloc->presumed_offset = 0; + reloc->read_domains = read_domain; + reloc->write_domain = write_domain; + + return reloc->presumed_offset + reloc->delta; +} + +static void +copy(int fd, + uint32_t dst, int dst_tiling, + uint32_t src, int src_tiling) +{ + uint32_t batch[1024], *b = batch; + struct drm_i915_gem_relocation_entry reloc[2], *r = reloc; + struct drm_i915_gem_exec_object2 obj[3]; + struct drm_i915_gem_execbuffer2 exec; + uint32_t handle; + uint32_t tiling_bits; + int ret; + + /* invariant state */ + *b++ = (_3DSTATE_AA_CMD | + AA_LINE_ECAAR_WIDTH_ENABLE | + AA_LINE_ECAAR_WIDTH_1_0 | + AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0); + *b++ = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD | + IAB_MODIFY_ENABLE | + IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) | + IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE << + IAB_SRC_FACTOR_SHIFT) | + IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO << + IAB_DST_FACTOR_SHIFT)); + *b++ = (_3DSTATE_DFLT_DIFFUSE_CMD); + *b++ = (0); + *b++ = (_3DSTATE_DFLT_SPEC_CMD); + *b++ = (0); + *b++ = (_3DSTATE_DFLT_Z_CMD); + *b++ = (0); + *b++ = (_3DSTATE_COORD_SET_BINDINGS | + CSB_TCB(0, 0) | + CSB_TCB(1, 1) | + CSB_TCB(2, 2) | + CSB_TCB(3, 3) | + CSB_TCB(4, 4) | + CSB_TCB(5, 5) | CSB_TCB(6, 6) | CSB_TCB(7, 7)); + *b++ = (_3DSTATE_RASTER_RULES_CMD | + ENABLE_POINT_RASTER_RULE | + OGL_POINT_RASTER_RULE | + ENABLE_LINE_STRIP_PROVOKE_VRTX | + ENABLE_TRI_FAN_PROVOKE_VRTX | + LINE_STRIP_PROVOKE_VRTX(1) | + TRI_FAN_PROVOKE_VRTX(2) | ENABLE_TEXKILL_3D_4D | TEXKILL_4D); + *b++ = (_3DSTATE_MODES_4_CMD | + ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) | + ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) | + ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff)); + *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2); + *b++ = (0x00000000); /* Disable texture coordinate wrap-shortest */ + *b++ = ((1 << S4_POINT_WIDTH_SHIFT) | + S4_LINE_WIDTH_ONE | + S4_CULLMODE_NONE | + S4_VFMT_XY); + *b++ = (0x00000000); /* Stencil. */ + *b++ = (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT); + *b++ = (_3DSTATE_SCISSOR_RECT_0_CMD); + *b++ = (0); + *b++ = (0); + *b++ = (_3DSTATE_DEPTH_SUBRECT_DISABLE); + *b++ = (_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */ + *b++ = (0); + *b++ = (_3DSTATE_STIPPLE); + *b++ = (0x00000000); + *b++ = (_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0); + + /* samler state */ + tiling_bits = 0; + if (src_tiling != I915_TILING_NONE) + tiling_bits = MS3_TILED_SURFACE; + if (src_tiling == I915_TILING_Y) + tiling_bits |= MS3_TILE_WALK; + +#define TEX_COUNT 1 + *b++ = (_3DSTATE_MAP_STATE | (3 * TEX_COUNT)); + *b++ = ((1 << TEX_COUNT) - 1); + *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_SAMPLER, 0); b++; + *b++ = (MAPSURF_32BIT | MT_32BIT_ARGB8888 | tiling_bits | + (HEIGHT - 1) << MS3_HEIGHT_SHIFT | + (WIDTH - 1) << MS3_WIDTH_SHIFT); + *b++ = ((WIDTH-1) << MS4_PITCH_SHIFT); + + *b++ = (_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT)); + *b++ = ((1 << TEX_COUNT) - 1); + *b++ = (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT | + FILTER_NEAREST << SS2_MAG_FILTER_SHIFT | + FILTER_NEAREST << SS2_MIN_FILTER_SHIFT); + *b++ = (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT | + TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT | + 0 << SS3_TEXTUREMAP_INDEX_SHIFT); + *b++ = (0x00000000); + + /* render target state */ + tiling_bits = 0; + if (dst_tiling != I915_TILING_NONE) + tiling_bits = BUF_3D_TILED_SURFACE; + if (dst_tiling == I915_TILING_Y) + tiling_bits |= BUF_3D_TILE_WALK_Y; + *b++ = (_3DSTATE_BUF_INFO_CMD); + *b++ = (BUF_3D_ID_COLOR_BACK | tiling_bits | WIDTH*4); + *b = fill_reloc(r++, b-batch, dst, + I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); + b++; + + *b++ = (_3DSTATE_DST_BUF_VARS_CMD); + *b++ = (COLR_BUF_ARGB8888 | + DSTORG_HORT_BIAS(0x8) | + DSTORG_VERT_BIAS(0x8)); + + /* draw rect is unconditional */ + *b++ = (_3DSTATE_DRAW_RECT_CMD); + *b++ = (0x00000000); + *b++ = (0x00000000); /* ymin, xmin */ + *b++ = (DRAW_YMAX(HEIGHT - 1) | + DRAW_XMAX(WIDTH - 1)); + /* yorig, xorig (relate to color buffer?) */ + *b++ = (0x00000000); + + /* texfmt */ + *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2); + *b++ = ((4 << S1_VERTEX_WIDTH_SHIFT) | (4 << S1_VERTEX_PITCH_SHIFT)); + *b++ = (~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D)); + *b++ = (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE | + BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT | + BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT | + BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT); + + /* pixel shader */ + *b++ = (_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2)); + /* decl FS_T0 */ + *b++ = (D0_DCL | + REG_TYPE(FS_T0) << D0_TYPE_SHIFT | + REG_NR(FS_T0) << D0_NR_SHIFT | + ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + *b++ = (0); + *b++ = (0); + /* decl FS_S0 */ + *b++ = (D0_DCL | + (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) | + (REG_NR(FS_S0) << D0_NR_SHIFT) | + ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + *b++ = (0); + *b++ = (0); + /* texld(FS_OC, FS_S0, FS_T0 */ + *b++ = (T0_TEXLD | + (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) | + (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) | + (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT)); + *b++ = ((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) | + (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT)); + *b++ = (0); + + *b++ = (PRIM3D_RECTLIST | (3*4 - 1)); + *b++ = pack_float(WIDTH); + *b++ = pack_float(HEIGHT); + *b++ = pack_float(WIDTH); + *b++ = pack_float(HEIGHT); + + *b++ = pack_float(0); + *b++ = pack_float(HEIGHT); + *b++ = pack_float(0); + *b++ = pack_float(HEIGHT); + + *b++ = pack_float(0); + *b++ = pack_float(0); + *b++ = pack_float(0); + *b++ = pack_float(0); + + *b++ = MI_BATCH_BUFFER_END; + if ((b - batch) & 1) + *b++ = 0; + + assert(b - batch <= 1024); + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0])); + + assert(r-reloc == 2); + + obj[0].handle = dst; + obj[0].relocation_count = 0; + obj[0].relocs_ptr = 0; + obj[0].alignment = 0; + obj[0].offset = 0; + obj[0].flags = 0; + obj[0].rsvd1 = 0; + obj[0].rsvd2 = 0; + + obj[1].handle = src; + obj[1].relocation_count = 0; + obj[1].relocs_ptr = 0; + obj[1].alignment = 0; + obj[1].offset = 0; + obj[1].flags = 0; + obj[1].rsvd1 = 0; + obj[1].rsvd2 = 0; + + obj[2].handle = handle; + obj[2].relocation_count = 2; + obj[2].relocs_ptr = (uintptr_t)reloc; + obj[2].alignment = 0; + obj[2].offset = 0; + obj[2].flags = 0; + obj[2].rsvd1 = obj[2].rsvd2 = 0; + + exec.buffers_ptr = (uintptr_t)obj; + exec.buffer_count = 3; + exec.batch_start_offset = 0; + exec.batch_len = (b-batch)*sizeof(batch[0]); + exec.DR1 = exec.DR4 = 0; + exec.num_cliprects = 0; + exec.cliprects_ptr = 0; + exec.flags = 0; + i915_execbuffer2_set_context_id(exec, 0); + exec.rsvd2 = 0; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + while (ret && errno == EBUSY) { + drmCommandNone(fd, DRM_I915_GEM_THROTTLE); + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + } + assert(ret == 0); + + gem_close(fd, handle); +} + +static uint32_t +create_bo(int fd, uint32_t val, int tiling) +{ + uint32_t handle; + uint32_t *v; + int i; + + handle = gem_create(fd, WIDTH*HEIGHT*4); + gem_set_tiling(fd, handle, tiling, WIDTH*4); + + /* Fill the BO with dwords starting at val */ + v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ | PROT_WRITE); + assert(v); + for (i = 0; i < WIDTH*HEIGHT; i++) + v[i] = val++; + munmap(v, WIDTH*HEIGHT*4); + + return handle; +} + +static void +check_bo(int fd, uint32_t handle, uint32_t val) +{ + uint32_t *v; + int i; + + v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ); + assert(v); + for (i = 0; i < WIDTH*HEIGHT; i++) { + if (v[i] != val) { + fprintf(stderr, "Expected 0x%08x, found 0x%08x " + "at offset 0x%08x\n", + val, v[i], i * 4); + abort(); + } + val++; + } + munmap(v, WIDTH*HEIGHT*4); +} + +int main(int argc, char **argv) +{ + uint32_t *handle, *tiling, *start_val; + uint32_t start = 0; + int i, fd, count; + + fd = drm_open_any(); + + if (!IS_GEN3(intel_get_drm_devid(fd))) { + printf("gen3-only test, doing nothing\n"); + return 77; + } + + count = 0; + if (argc > 1) + count = atoi(argv[1]); + if (count == 0) + count = 3 * gem_aperture_size(fd) / (1024*1024) / 2; + printf("Using %d 1MiB buffers\n", count); + + handle = malloc(sizeof(uint32_t)*count*3); + tiling = handle + count; + start_val = tiling + count; + + for (i = 0; i < count; i++) { + handle[i] = create_bo(fd, start, tiling[i] = i % 3); + start_val[i] = start; + start += 1024 * 1024 / 4; + } + + printf("Verifying initialisation..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + printf("Cyclic blits, forward..."); fflush(stdout); + for (i = 0; i < count * 32; i++) { + int src = i % count; + int dst = (i + 1) % count; + + copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]); + start_val[dst] = start_val[src]; + } + printf("verifying..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + printf("Cyclic blits, backward..."); fflush(stdout); + for (i = 0; i < count * 32; i++) { + int src = (i + 1) % count; + int dst = i % count; + + copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]); + start_val[dst] = start_val[src]; + } + printf("verifying..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + printf("Random blits..."); fflush(stdout); + for (i = 0; i < count * 32; i++) { + int src = random() % count; + int dst = random() % count; + + while (src == dst) + dst = random() % count; + + copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]); + start_val[dst] = start_val[src]; + } + printf("verifying..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + return 0; +} diff --git a/tests/gen3_render_tiledx_blits.c b/tests/gen3_render_tiledx_blits.c new file mode 100644 index 00000000..0e96e797 --- /dev/null +++ b/tests/gen3_render_tiledx_blits.c @@ -0,0 +1,408 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** @file gen3_linear_render_blits.c + * + * This is a test of doing many blits, with a working set + * larger than the aperture size. + * + * The goal is to simply ensure the basics work. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#include "i915_reg.h" +#include "i915_3d.h" + +#define WIDTH 512 +#define HEIGHT 512 + +static inline uint32_t pack_float(float f) +{ + union { + uint32_t dw; + float f; + } u; + u.f = f; + return u.dw; +} + +static uint32_t fill_reloc(struct drm_i915_gem_relocation_entry *reloc, + uint32_t offset, + uint32_t handle, + uint32_t read_domain, + uint32_t write_domain) +{ + reloc->target_handle = handle; + reloc->delta = 0; + reloc->offset = offset * sizeof(uint32_t); + reloc->presumed_offset = 0; + reloc->read_domains = read_domain; + reloc->write_domain = write_domain; + + return reloc->presumed_offset + reloc->delta; +} + +static void +copy(int fd, uint32_t dst, uint32_t src) +{ + uint32_t batch[1024], *b = batch; + struct drm_i915_gem_relocation_entry reloc[2], *r = reloc; + struct drm_i915_gem_exec_object2 obj[3]; + struct drm_i915_gem_execbuffer2 exec; + uint32_t handle; + int ret; + + /* invariant state */ + *b++ = (_3DSTATE_AA_CMD | + AA_LINE_ECAAR_WIDTH_ENABLE | + AA_LINE_ECAAR_WIDTH_1_0 | + AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0); + *b++ = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD | + IAB_MODIFY_ENABLE | + IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) | + IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE << + IAB_SRC_FACTOR_SHIFT) | + IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO << + IAB_DST_FACTOR_SHIFT)); + *b++ = (_3DSTATE_DFLT_DIFFUSE_CMD); + *b++ = (0); + *b++ = (_3DSTATE_DFLT_SPEC_CMD); + *b++ = (0); + *b++ = (_3DSTATE_DFLT_Z_CMD); + *b++ = (0); + *b++ = (_3DSTATE_COORD_SET_BINDINGS | + CSB_TCB(0, 0) | + CSB_TCB(1, 1) | + CSB_TCB(2, 2) | + CSB_TCB(3, 3) | + CSB_TCB(4, 4) | + CSB_TCB(5, 5) | CSB_TCB(6, 6) | CSB_TCB(7, 7)); + *b++ = (_3DSTATE_RASTER_RULES_CMD | + ENABLE_POINT_RASTER_RULE | + OGL_POINT_RASTER_RULE | + ENABLE_LINE_STRIP_PROVOKE_VRTX | + ENABLE_TRI_FAN_PROVOKE_VRTX | + LINE_STRIP_PROVOKE_VRTX(1) | + TRI_FAN_PROVOKE_VRTX(2) | ENABLE_TEXKILL_3D_4D | TEXKILL_4D); + *b++ = (_3DSTATE_MODES_4_CMD | + ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) | + ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) | + ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff)); + *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2); + *b++ = (0x00000000); /* Disable texture coordinate wrap-shortest */ + *b++ = ((1 << S4_POINT_WIDTH_SHIFT) | + S4_LINE_WIDTH_ONE | + S4_CULLMODE_NONE | + S4_VFMT_XY); + *b++ = (0x00000000); /* Stencil. */ + *b++ = (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT); + *b++ = (_3DSTATE_SCISSOR_RECT_0_CMD); + *b++ = (0); + *b++ = (0); + *b++ = (_3DSTATE_DEPTH_SUBRECT_DISABLE); + *b++ = (_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */ + *b++ = (0); + *b++ = (_3DSTATE_STIPPLE); + *b++ = (0x00000000); + *b++ = (_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0); + + /* samler state */ +#define TEX_COUNT 1 + *b++ = (_3DSTATE_MAP_STATE | (3 * TEX_COUNT)); + *b++ = ((1 << TEX_COUNT) - 1); + *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_SAMPLER, 0); b++; + *b++ = (MAPSURF_32BIT | MT_32BIT_ARGB8888 | + MS3_TILED_SURFACE | + (HEIGHT - 1) << MS3_HEIGHT_SHIFT | + (WIDTH - 1) << MS3_WIDTH_SHIFT); + *b++ = ((WIDTH-1) << MS4_PITCH_SHIFT); + + *b++ = (_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT)); + *b++ = ((1 << TEX_COUNT) - 1); + *b++ = (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT | + FILTER_NEAREST << SS2_MAG_FILTER_SHIFT | + FILTER_NEAREST << SS2_MIN_FILTER_SHIFT); + *b++ = (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT | + TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT | + 0 << SS3_TEXTUREMAP_INDEX_SHIFT); + *b++ = (0x00000000); + + /* render target state */ + *b++ = (_3DSTATE_BUF_INFO_CMD); + *b++ = (BUF_3D_ID_COLOR_BACK | BUF_3D_TILED_SURFACE | WIDTH*4); + *b = fill_reloc(r++, b-batch, dst, + I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); + b++; + + *b++ = (_3DSTATE_DST_BUF_VARS_CMD); + *b++ = (COLR_BUF_ARGB8888 | + DSTORG_HORT_BIAS(0x8) | + DSTORG_VERT_BIAS(0x8)); + + /* draw rect is unconditional */ + *b++ = (_3DSTATE_DRAW_RECT_CMD); + *b++ = (0x00000000); + *b++ = (0x00000000); /* ymin, xmin */ + *b++ = (DRAW_YMAX(HEIGHT - 1) | + DRAW_XMAX(WIDTH - 1)); + /* yorig, xorig (relate to color buffer?) */ + *b++ = (0x00000000); + + /* texfmt */ + *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2); + *b++ = ((4 << S1_VERTEX_WIDTH_SHIFT) | (4 << S1_VERTEX_PITCH_SHIFT)); + *b++ = (~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D)); + *b++ = (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE | + BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT | + BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT | + BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT); + + /* pixel shader */ + *b++ = (_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2)); + /* decl FS_T0 */ + *b++ = (D0_DCL | + REG_TYPE(FS_T0) << D0_TYPE_SHIFT | + REG_NR(FS_T0) << D0_NR_SHIFT | + ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + *b++ = (0); + *b++ = (0); + /* decl FS_S0 */ + *b++ = (D0_DCL | + (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) | + (REG_NR(FS_S0) << D0_NR_SHIFT) | + ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + *b++ = (0); + *b++ = (0); + /* texld(FS_OC, FS_S0, FS_T0 */ + *b++ = (T0_TEXLD | + (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) | + (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) | + (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT)); + *b++ = ((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) | + (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT)); + *b++ = (0); + + *b++ = (PRIM3D_RECTLIST | (3*4 - 1)); + *b++ = pack_float(WIDTH); + *b++ = pack_float(HEIGHT); + *b++ = pack_float(WIDTH); + *b++ = pack_float(HEIGHT); + + *b++ = pack_float(0); + *b++ = pack_float(HEIGHT); + *b++ = pack_float(0); + *b++ = pack_float(HEIGHT); + + *b++ = pack_float(0); + *b++ = pack_float(0); + *b++ = pack_float(0); + *b++ = pack_float(0); + + *b++ = MI_BATCH_BUFFER_END; + if ((b - batch) & 1) + *b++ = 0; + + assert(b - batch <= 1024); + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0])); + + assert(r-reloc == 2); + + obj[0].handle = dst; + obj[0].relocation_count = 0; + obj[0].relocs_ptr = 0; + obj[0].alignment = 0; + obj[0].offset = 0; + obj[0].flags = 0; + obj[0].rsvd1 = 0; + obj[0].rsvd2 = 0; + + obj[1].handle = src; + obj[1].relocation_count = 0; + obj[1].relocs_ptr = 0; + obj[1].alignment = 0; + obj[1].offset = 0; + obj[1].flags = 0; + obj[1].rsvd1 = 0; + obj[1].rsvd2 = 0; + + obj[2].handle = handle; + obj[2].relocation_count = 2; + obj[2].relocs_ptr = (uintptr_t)reloc; + obj[2].alignment = 0; + obj[2].offset = 0; + obj[2].flags = 0; + obj[2].rsvd1 = obj[2].rsvd2 = 0; + + exec.buffers_ptr = (uintptr_t)obj; + exec.buffer_count = 3; + exec.batch_start_offset = 0; + exec.batch_len = (b-batch)*sizeof(batch[0]); + exec.DR1 = exec.DR4 = 0; + exec.num_cliprects = 0; + exec.cliprects_ptr = 0; + exec.flags = 0; + i915_execbuffer2_set_context_id(exec, 0); + exec.rsvd2 = 0; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + while (ret && errno == EBUSY) { + drmCommandNone(fd, DRM_I915_GEM_THROTTLE); + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + } + assert(ret == 0); + + gem_close(fd, handle); +} + +static uint32_t +create_bo(int fd, uint32_t val) +{ + uint32_t handle; + uint32_t *v; + int i; + + handle = gem_create(fd, WIDTH*HEIGHT*4); + gem_set_tiling(fd, handle, I915_TILING_X, WIDTH*4); + + /* Fill the BO with dwords starting at val */ + v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ | PROT_WRITE); + assert(v); + for (i = 0; i < WIDTH*HEIGHT; i++) + v[i] = val++; + munmap(v, WIDTH*HEIGHT*4); + + return handle; +} + +static void +check_bo(int fd, uint32_t handle, uint32_t val) +{ + uint32_t *v; + int i; + + v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ); + assert(v); + for (i = 0; i < WIDTH*HEIGHT; i++) { + if (v[i] != val) { + fprintf(stderr, "Expected 0x%08x, found 0x%08x " + "at offset 0x%08x\n", + val, v[i], i * 4); + abort(); + } + val++; + } + munmap(v, WIDTH*HEIGHT*4); +} + +int main(int argc, char **argv) +{ + uint32_t *handle, *start_val; + uint32_t start = 0; + int i, fd, count; + + fd = drm_open_any(); + + if (!IS_GEN3(intel_get_drm_devid(fd))) { + printf("gen3-only test, doing nothing\n"); + return 77; + } + + count = 0; + if (argc > 1) + count = atoi(argv[1]); + if (count == 0) + count = 3 * gem_aperture_size(fd) / (1024*1024) / 2; + printf("Using %d 1MiB buffers\n", count); + + handle = malloc(sizeof(uint32_t)*count*2); + start_val = handle + count; + + for (i = 0; i < count; i++) { + handle[i] = create_bo(fd, start); + start_val[i] = start; + start += 1024 * 1024 / 4; + } + + printf("Verifying initialisation...\n"); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + printf("Cyclic blits, forward...\n"); + for (i = 0; i < count * 4; i++) { + int src = i % count; + int dst = (i + 1) % count; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + printf("Cyclic blits, backward...\n"); + for (i = 0; i < count * 4; i++) { + int src = (i + 1) % count; + int dst = i % count; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + printf("Random blits...\n"); + for (i = 0; i < count * 4; i++) { + int src = random() % count; + int dst = random() % count; + + if (src == dst) + continue; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + + return 0; +} diff --git a/tests/gen3_render_tiledy_blits.c b/tests/gen3_render_tiledy_blits.c new file mode 100644 index 00000000..90fc7eb9 --- /dev/null +++ b/tests/gen3_render_tiledy_blits.c @@ -0,0 +1,415 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** @file gen3_linear_render_blits.c + * + * This is a test of doing many blits, with a working set + * larger than the aperture size. + * + * The goal is to simply ensure the basics work. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +#include "i915_reg.h" +#include "i915_3d.h" + +#define WIDTH 512 +#define HEIGHT 512 + +static inline uint32_t pack_float(float f) +{ + union { + uint32_t dw; + float f; + } u; + u.f = f; + return u.dw; +} + +static uint32_t fill_reloc(struct drm_i915_gem_relocation_entry *reloc, + uint32_t offset, + uint32_t handle, + uint32_t read_domain, + uint32_t write_domain) +{ + reloc->target_handle = handle; + reloc->delta = 0; + reloc->offset = offset * sizeof(uint32_t); + reloc->presumed_offset = 0; + reloc->read_domains = read_domain; + reloc->write_domain = write_domain; + + return reloc->presumed_offset + reloc->delta; +} + +static void +copy(int fd, uint32_t dst, uint32_t src) +{ + uint32_t batch[1024], *b = batch; + struct drm_i915_gem_relocation_entry reloc[2], *r = reloc; + struct drm_i915_gem_exec_object2 obj[3]; + struct drm_i915_gem_execbuffer2 exec; + uint32_t handle; + int ret; + + /* invariant state */ + *b++ = (_3DSTATE_AA_CMD | + AA_LINE_ECAAR_WIDTH_ENABLE | + AA_LINE_ECAAR_WIDTH_1_0 | + AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0); + *b++ = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD | + IAB_MODIFY_ENABLE | + IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) | + IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE << + IAB_SRC_FACTOR_SHIFT) | + IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO << + IAB_DST_FACTOR_SHIFT)); + *b++ = (_3DSTATE_DFLT_DIFFUSE_CMD); + *b++ = (0); + *b++ = (_3DSTATE_DFLT_SPEC_CMD); + *b++ = (0); + *b++ = (_3DSTATE_DFLT_Z_CMD); + *b++ = (0); + *b++ = (_3DSTATE_COORD_SET_BINDINGS | + CSB_TCB(0, 0) | + CSB_TCB(1, 1) | + CSB_TCB(2, 2) | + CSB_TCB(3, 3) | + CSB_TCB(4, 4) | + CSB_TCB(5, 5) | CSB_TCB(6, 6) | CSB_TCB(7, 7)); + *b++ = (_3DSTATE_RASTER_RULES_CMD | + ENABLE_POINT_RASTER_RULE | + OGL_POINT_RASTER_RULE | + ENABLE_LINE_STRIP_PROVOKE_VRTX | + ENABLE_TRI_FAN_PROVOKE_VRTX | + LINE_STRIP_PROVOKE_VRTX(1) | + TRI_FAN_PROVOKE_VRTX(2) | ENABLE_TEXKILL_3D_4D | TEXKILL_4D); + *b++ = (_3DSTATE_MODES_4_CMD | + ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) | + ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) | + ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff)); + *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2); + *b++ = (0x00000000); /* Disable texture coordinate wrap-shortest */ + *b++ = ((1 << S4_POINT_WIDTH_SHIFT) | + S4_LINE_WIDTH_ONE | + S4_CULLMODE_NONE | + S4_VFMT_XY); + *b++ = (0x00000000); /* Stencil. */ + *b++ = (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT); + *b++ = (_3DSTATE_SCISSOR_RECT_0_CMD); + *b++ = (0); + *b++ = (0); + *b++ = (_3DSTATE_DEPTH_SUBRECT_DISABLE); + *b++ = (_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */ + *b++ = (0); + *b++ = (_3DSTATE_STIPPLE); + *b++ = (0x00000000); + *b++ = (_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0); + + /* samler state */ +#define TEX_COUNT 1 + *b++ = (_3DSTATE_MAP_STATE | (3 * TEX_COUNT)); + *b++ = ((1 << TEX_COUNT) - 1); + *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_SAMPLER, 0); b++; + *b++ = (MAPSURF_32BIT | MT_32BIT_ARGB8888 | + MS3_TILED_SURFACE | MS3_TILE_WALK | + (HEIGHT - 1) << MS3_HEIGHT_SHIFT | + (WIDTH - 1) << MS3_WIDTH_SHIFT); + *b++ = ((WIDTH-1) << MS4_PITCH_SHIFT); + + *b++ = (_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT)); + *b++ = ((1 << TEX_COUNT) - 1); + *b++ = (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT | + FILTER_NEAREST << SS2_MAG_FILTER_SHIFT | + FILTER_NEAREST << SS2_MIN_FILTER_SHIFT); + *b++ = (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT | + TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT | + 0 << SS3_TEXTUREMAP_INDEX_SHIFT); + *b++ = (0x00000000); + + /* render target state */ + *b++ = (_3DSTATE_BUF_INFO_CMD); + *b++ = (BUF_3D_ID_COLOR_BACK | BUF_3D_TILED_SURFACE | BUF_3D_TILE_WALK_Y | WIDTH*4); + *b = fill_reloc(r++, b-batch, dst, + I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); + b++; + + *b++ = (_3DSTATE_DST_BUF_VARS_CMD); + *b++ = (COLR_BUF_ARGB8888 | + DSTORG_HORT_BIAS(0x8) | + DSTORG_VERT_BIAS(0x8)); + + /* draw rect is unconditional */ + *b++ = (_3DSTATE_DRAW_RECT_CMD); + *b++ = (0x00000000); + *b++ = (0x00000000); /* ymin, xmin */ + *b++ = (DRAW_YMAX(HEIGHT - 1) | + DRAW_XMAX(WIDTH - 1)); + /* yorig, xorig (relate to color buffer?) */ + *b++ = (0x00000000); + + /* texfmt */ + *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2); + *b++ = ((4 << S1_VERTEX_WIDTH_SHIFT) | (4 << S1_VERTEX_PITCH_SHIFT)); + *b++ = (~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D)); + *b++ = (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE | + BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT | + BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT | + BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT); + + /* pixel shader */ + *b++ = (_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2)); + /* decl FS_T0 */ + *b++ = (D0_DCL | + REG_TYPE(FS_T0) << D0_TYPE_SHIFT | + REG_NR(FS_T0) << D0_NR_SHIFT | + ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + *b++ = (0); + *b++ = (0); + /* decl FS_S0 */ + *b++ = (D0_DCL | + (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) | + (REG_NR(FS_S0) << D0_NR_SHIFT) | + ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); + *b++ = (0); + *b++ = (0); + /* texld(FS_OC, FS_S0, FS_T0 */ + *b++ = (T0_TEXLD | + (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) | + (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) | + (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT)); + *b++ = ((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) | + (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT)); + *b++ = (0); + + *b++ = (PRIM3D_RECTLIST | (3*4 - 1)); + *b++ = pack_float(WIDTH); + *b++ = pack_float(HEIGHT); + *b++ = pack_float(WIDTH); + *b++ = pack_float(HEIGHT); + + *b++ = pack_float(0); + *b++ = pack_float(HEIGHT); + *b++ = pack_float(0); + *b++ = pack_float(HEIGHT); + + *b++ = pack_float(0); + *b++ = pack_float(0); + *b++ = pack_float(0); + *b++ = pack_float(0); + + *b++ = MI_BATCH_BUFFER_END; + if ((b - batch) & 1) + *b++ = 0; + + assert(b - batch <= 1024); + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0])); + + assert(r-reloc == 2); + + obj[0].handle = dst; + obj[0].relocation_count = 0; + obj[0].relocs_ptr = 0; + obj[0].alignment = 0; + obj[0].offset = 0; + obj[0].flags = 0; + obj[0].rsvd1 = 0; + obj[0].rsvd2 = 0; + + obj[1].handle = src; + obj[1].relocation_count = 0; + obj[1].relocs_ptr = 0; + obj[1].alignment = 0; + obj[1].offset = 0; + obj[1].flags = 0; + obj[1].rsvd1 = 0; + obj[1].rsvd2 = 0; + + obj[2].handle = handle; + obj[2].relocation_count = 2; + obj[2].relocs_ptr = (uintptr_t)reloc; + obj[2].alignment = 0; + obj[2].offset = 0; + obj[2].flags = 0; + obj[2].rsvd1 = obj[2].rsvd2 = 0; + + exec.buffers_ptr = (uintptr_t)obj; + exec.buffer_count = 3; + exec.batch_start_offset = 0; + exec.batch_len = (b-batch)*sizeof(batch[0]); + exec.DR1 = exec.DR4 = 0; + exec.num_cliprects = 0; + exec.cliprects_ptr = 0; + exec.flags = 0; + i915_execbuffer2_set_context_id(exec, 0); + exec.rsvd2 = 0; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + while (ret && errno == EBUSY) { + drmCommandNone(fd, DRM_I915_GEM_THROTTLE); + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec); + } + assert(ret == 0); + + gem_close(fd, handle); +} + +static uint32_t +create_bo(int fd, uint32_t val) +{ + uint32_t handle; + uint32_t *v; + int i; + + handle = gem_create(fd, WIDTH*HEIGHT*4); + gem_set_tiling(fd, handle, I915_TILING_Y, WIDTH*4); + + /* Fill the BO with dwords starting at val */ + v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ | PROT_WRITE); + assert(v); + for (i = 0; i < WIDTH*HEIGHT; i++) + v[i] = val++; + munmap(v, WIDTH*HEIGHT*4); + + return handle; +} + +static void +check_bo(int fd, uint32_t handle, uint32_t val) +{ + uint32_t *v; + int i; + + v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ); + assert(v); + for (i = 0; i < WIDTH*HEIGHT; i++) { + if (v[i] != val) { + fprintf(stderr, "Expected 0x%08x, found 0x%08x " + "at offset 0x%08x\n", + val, v[i], i * 4); + abort(); + } + val++; + } + munmap(v, WIDTH*HEIGHT*4); +} + +int main(int argc, char **argv) +{ + uint32_t *handle, *start_val; + uint32_t start = 0; + int i, fd, count; + + fd = drm_open_any(); + + if (!IS_GEN3(intel_get_drm_devid(fd))) { + printf("gen3-only test, doing nothing\n"); + return 77; + } + + count = 0; + if (argc > 1) + count = atoi(argv[1]); + if (count == 0) + count = 3 * gem_aperture_size(fd) / (1024*1024) / 2; + printf("Using %d 1MiB buffers\n", count); + + handle = malloc(sizeof(uint32_t)*count*2); + start_val = handle + count; + + for (i = 0; i < count; i++) { + handle[i] = create_bo(fd, start); + start_val[i] = start; + start += 1024 * 1024 / 4; + } + + printf("Verifying initialisation..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + printf("Cyclic blits, forward..."); fflush(stdout); + for (i = 0; i < count * 32; i++) { + int src = i % count; + int dst = (i + 1) % count; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + printf("verifying..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + printf("Cyclic blits, backward..."); fflush(stdout); + for (i = 0; i < count * 32; i++) { + int src = (i + 1) % count; + int dst = i % count; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + printf("verifying..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + printf("Random blits..."); fflush(stdout); + for (i = 0; i < count * 32; i++) { + int src = random() % count; + int dst = random() % count; + + while (src == dst) + dst = random() % count; + + copy(fd, handle[dst], handle[src]); + start_val[dst] = start_val[src]; + } + printf("verifying..."); fflush(stdout); + for (i = 0; i < count; i++) + check_bo(fd, handle[i], start_val[i]); + printf("done\n"); + + return 0; +} diff --git a/tests/getclient.c b/tests/getclient.c new file mode 100644 index 00000000..481ce119 --- /dev/null +++ b/tests/getclient.c @@ -0,0 +1,61 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <limits.h> +#include <sys/ioctl.h> +#include "drmtest.h" + +/** + * Checks DRM_IOCTL_GET_CLIENT. + */ +int main(int argc, char **argv) +{ + int fd, ret; + drm_client_t client; + + fd = drm_open_any(); + + /* Look for client index 0. This should exist whether we're operating + * on an otherwise unused drm device, or the X Server is running on + * the device. + */ + client.idx = 0; + ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client); + assert(ret == 0); + + /* Look for some absurd client index and make sure it's invalid. + * The DRM drivers currently always return data, so the user has + * no real way to detect when the list has terminated. That's bad, + * and this test is XFAIL as a result. + */ + client.idx = 0x7fffffff; + ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client); + assert(ret == -1 && errno == EINVAL); + + close(fd); + return 0; +} diff --git a/tests/getstats.c b/tests/getstats.c new file mode 100644 index 00000000..8a7d2999 --- /dev/null +++ b/tests/getstats.c @@ -0,0 +1,50 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <limits.h> +#include <sys/ioctl.h> +#include "drmtest.h" + +/** + * Checks DRM_IOCTL_GET_STATS. + * + * I don't care too much about the actual contents, just that the kernel + * doesn't crash. + */ +int main(int argc, char **argv) +{ + int fd, ret; + drm_stats_t stats; + + fd = drm_open_any(); + + ret = ioctl(fd, DRM_IOCTL_GET_STATS, &stats); + assert(ret == 0); + + close(fd); + return 0; +} diff --git a/tests/getversion.c b/tests/getversion.c new file mode 100644 index 00000000..4847e796 --- /dev/null +++ b/tests/getversion.c @@ -0,0 +1,49 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <string.h> +#include <sys/ioctl.h> +#include "drmtest.h" + +/** + * Checks DRM_IOCTL_GET_VERSION and libdrm's drmGetVersion() interface to it. + */ +int main(int argc, char **argv) +{ + int fd; + drmVersionPtr v; + + fd = drm_open_any(); + v = drmGetVersion(fd); + assert(strlen(v->name) != 0); + assert(strlen(v->date) != 0); + assert(strlen(v->desc) != 0); + assert(v->version_major >= 1); + drmFree(v); + close(fd); + return 0; +} diff --git a/tests/module_reload b/tests/module_reload new file mode 100755 index 00000000..400fdd04 --- /dev/null +++ b/tests/module_reload @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Testcase: Reload the drm module +# +# ... we've broken this way too often :( +# + +SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )" +. $SOURCE_DIR/drm_lib.sh + +# no other drm service should be running, so we can just unbind + +# vtcon0 is vga, vtcon1 fbcon and let's pray that won't change due to boot load +# time changes +if ! echo 0 > /sys/class/vtconsole/vtcon1/bind ; then + echo -e "no kms unload support" + echo "please enable CONFIG_VT_HW_CONSOLE_BINDING in the kernel" + exit 77 +fi + +#ignore errors in ips - gen5 only +rmmod intel_ips &> /dev/null +rmmod i915 +#ignore errors in intel-gtt, often built-in +rmmod intel-gtt &> /dev/null +rmmod drm_kms_helper +rmmod drm + +if lsmod | grep i915 &> /dev/null ; then + echo WARNING: i915.ko still loaded! + exitcode=1 +else + echo module successfully unloaded + exitcode=0 +fi + +modprobe i915 +echo 1 > /sys/class/vtconsole/vtcon1/bind + +# try to run something +$SOURCE_DIR/gem_exec_nop > /dev/null && echo "module successfully loaded again" diff --git a/tests/pass.png b/tests/pass.png Binary files differnew file mode 100644 index 00000000..36a5236b --- /dev/null +++ b/tests/pass.png diff --git a/tests/prime_nv_api.c b/tests/prime_nv_api.c new file mode 100644 index 00000000..962e903d --- /dev/null +++ b/tests/prime_nv_api.c @@ -0,0 +1,408 @@ +/* wierd use of API tests */ + +/* test1- export buffer from intel, import same fd twice into nouveau, + check handles match + test2 - export buffer from intel, import fd once, close fd, try import again + fail if it succeeds + test3 - export buffer from intel, import twice on nouveau, check handle is the same + test4 - export handle twice from intel, import into nouveau twice, check handle is the same +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> + +#include "intel_bufmgr.h" +#include "nouveau.h" +#include "intel_gpu_tools.h" +#include "intel_batchbuffer.h" + +#define BO_SIZE (256*1024) + +int intel_fd = -1, intel_fd2 = -1, nouveau_fd = -1, nouveau_fd2 = -1; +drm_intel_bufmgr *bufmgr; +drm_intel_bufmgr *bufmgr2; +struct nouveau_device *ndev, *ndev2; +struct nouveau_client *nclient, *nclient2; +uint32_t devid; +struct intel_batchbuffer *intel_batch; + +static int find_and_open_devices(void) +{ + int i; + char path[80]; + struct stat buf; + FILE *fl; + char vendor_id[8]; + int venid; + for (i = 0; i < 9; i++) { + sprintf(path, "/sys/class/drm/card%d/device/vendor", i); + if (stat(path, &buf)) + break; + + fl = fopen(path, "r"); + if (!fl) + break; + + fgets(vendor_id, 8, fl); + fclose(fl); + + venid = strtoul(vendor_id, NULL, 16); + sprintf(path, "/dev/dri/card%d", i); + if (venid == 0x8086) { + intel_fd = open(path, O_RDWR); + if (!intel_fd) + return -1; + intel_fd2 = open(path, O_RDWR); + if (!intel_fd2) + return -1; + } else if (venid == 0x10de) { + nouveau_fd = open(path, O_RDWR); + if (!nouveau_fd) + return -1; + nouveau_fd2 = open(path, O_RDWR); + if (!nouveau_fd2) + return -1; + } + } + return 0; +} + +static int test1(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd; + struct nouveau_bo *nvbo = NULL, *nvbo2 = NULL; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096); + + ret = drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + if (ret) + goto out; + + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo); + if (ret < 0) { + close(prime_fd); + goto out; + } + ret = nouveau_bo_prime_handle_ref(ndev2, prime_fd, &nvbo2); + close(prime_fd); + if (ret < 0) + goto out; + + if (nvbo->handle != nvbo2->handle) + ret = -1; +out: + nouveau_bo_ref(NULL, &nvbo2); + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + + +static int test2(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd; + struct nouveau_bo *nvbo = NULL, *nvbo2 = NULL; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096); + + ret = drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + if (ret < 0) + goto out; + + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo); + close(prime_fd); + if (ret < 0) + goto out; + ret = nouveau_bo_prime_handle_ref(ndev2, prime_fd, &nvbo2); + if (ret == 0) + ret = -1; + else + ret = 0; + +out: + nouveau_bo_ref(NULL, &nvbo2); + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + + +/* import handle twice on one driver */ +static int test3(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd; + struct nouveau_bo *nvbo = NULL, *nvbo2 = NULL; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096); + + ret = drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + if (ret < 0) + goto out; + + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo); + if (ret < 0) { + close(prime_fd); + goto out; + } + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo2); + close(prime_fd); + if (ret < 0) + goto out; + + if (nvbo->handle != nvbo2->handle) + ret = -1; + +out: + nouveau_bo_ref(NULL, &nvbo2); + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +/* export handle twice from one driver - import twice + see if we get same object */ +static int test4(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd, prime_fd2; + struct nouveau_bo *nvbo = NULL, *nvbo2 = NULL; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096); + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd2); + + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo); + close(prime_fd); + if (ret >= 0) + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd2, &nvbo2); + close(prime_fd2); + if (ret < 0) + goto out; + + if (nvbo->handle != nvbo2->handle) + ret = -1; + +out: + nouveau_bo_ref(NULL, &nvbo2); + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +/* export handle from intel driver - reimport to intel driver + see if you get same object */ +static int test5(void) +{ + int ret; + drm_intel_bo *test_intel_bo, *test_intel_bo2; + int prime_fd; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096); + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + + test_intel_bo2 = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE); + close(prime_fd); + if (!test_intel_bo2) { + ret = -1; + goto out; + } + + ret = 0; + if (test_intel_bo->handle != test_intel_bo2->handle) + ret = -1; + +out: + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +/* nouveau export reimport test */ +static int test6(void) +{ + int ret; + int prime_fd; + struct nouveau_bo *nvbo, *nvbo2; + + ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, + 0, BO_SIZE, NULL, &nvbo); + if (ret < 0) + return ret; + ret = nouveau_bo_set_prime(nvbo, &prime_fd); + if (ret < 0) + return ret; + + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo2); + close(prime_fd); + if (ret < 0) + return ret; + + if (nvbo->handle != nvbo2->handle) + fprintf(stderr,"mismatch handles %d %d\n", nvbo->handle, nvbo2->handle); + nouveau_bo_ref(NULL, &nvbo); + nouveau_bo_ref(NULL, &nvbo2); + return 0; +} + +/* export handle from intel driver - reimport to another intel driver bufmgr + see if you get same object */ +static int test7(void) +{ + int ret; + drm_intel_bo *test_intel_bo, *test_intel_bo2; + int prime_fd; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096); + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + + test_intel_bo2 = drm_intel_bo_gem_create_from_prime(bufmgr2, prime_fd, BO_SIZE); + close(prime_fd); + if (!test_intel_bo2) { + ret = -1; + goto out; + } + + ret = 0; + /* not sure what to test for, just that we don't explode */ +out: + drm_intel_bo_unreference(test_intel_bo2); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +/* nouveau export reimport to other driver test */ +static int test8(void) +{ + int ret; + int prime_fd; + struct nouveau_bo *nvbo, *nvbo2; + + ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, + 0, BO_SIZE, NULL, &nvbo); + if (ret < 0) + return ret; + ret = nouveau_bo_set_prime(nvbo, &prime_fd); + if (ret < 0) + return ret; + + ret = nouveau_bo_prime_handle_ref(ndev2, prime_fd, &nvbo2); + close(prime_fd); + if (ret < 0) + return ret; + + /* not sure what to test for, just make sure we don't explode */ + nouveau_bo_ref(NULL, &nvbo); + nouveau_bo_ref(NULL, &nvbo2); + return 0; +} + +int main(int argc, char **argv) +{ + int ret; + + ret = find_and_open_devices(); + if (ret < 0) + return ret; + + if (nouveau_fd == -1 || intel_fd == -1 || nouveau_fd2 == -1 || intel_fd2 == -1) { + fprintf(stderr,"failed to find intel and nouveau GPU\n"); + return 77; + } + + /* set up intel bufmgr */ + bufmgr = drm_intel_bufmgr_gem_init(intel_fd, 4096); + if (!bufmgr) + return -1; + /* Do not enable reuse, we share (almost) all buffers. */ + //drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + bufmgr2 = drm_intel_bufmgr_gem_init(intel_fd2, 4096); + if (!bufmgr2) + return -1; + drm_intel_bufmgr_gem_enable_reuse(bufmgr2); + + /* set up nouveau bufmgr */ + ret = nouveau_device_wrap(nouveau_fd, 0, &ndev); + if (ret < 0) { + fprintf(stderr,"failed to wrap nouveau device\n"); + return 77; + } + + ret = nouveau_client_new(ndev, &nclient); + if (ret < 0) { + fprintf(stderr,"failed to setup nouveau client\n"); + return -1; + } + + /* set up nouveau bufmgr */ + ret = nouveau_device_wrap(nouveau_fd2, 0, &ndev2); + if (ret < 0) { + fprintf(stderr,"failed to wrap nouveau device\n"); + return 77; + } + + ret = nouveau_client_new(ndev2, &nclient2); + if (ret < 0) { + fprintf(stderr,"failed to setup nouveau client\n"); + return -1; + } + + /* set up an intel batch buffer */ + devid = intel_get_drm_devid(intel_fd); + intel_batch = intel_batchbuffer_alloc(bufmgr, devid); + + ret = test1(); + if (ret) + fprintf(stderr,"prime_test: failed test 1\n"); + + ret = test2(); + if (ret) + fprintf(stderr,"prime_test: failed test 2\n"); + + ret = test3(); + if (ret) + fprintf(stderr,"prime_test: failed test 3\n"); + + ret = test4(); + if (ret) + fprintf(stderr,"prime_test: failed test 4\n"); + + ret = test5(); + if (ret) + fprintf(stderr,"prime_test: failed test 5\n"); + + ret = test6(); + if (ret) + fprintf(stderr,"prime_test: failed test 6\n"); + + ret = test7(); + if (ret) + fprintf(stderr,"prime_test: failed test 7\n"); + + ret = test8(); + if (ret) + fprintf(stderr,"prime_test: failed test 8\n"); + + intel_batchbuffer_free(intel_batch); + + nouveau_device_del(&ndev); + drm_intel_bufmgr_destroy(bufmgr); + + close(intel_fd); + close(nouveau_fd); + + return ret; +} diff --git a/tests/prime_nv_pcopy.c b/tests/prime_nv_pcopy.c new file mode 100644 index 00000000..21dccf38 --- /dev/null +++ b/tests/prime_nv_pcopy.c @@ -0,0 +1,1329 @@ +/* basic set of prime tests between intel and nouveau */ + +/* test list - + 1. share buffer from intel -> nouveau. + 2. share buffer from nouveau -> intel + 3. share intel->nouveau, map on both, write intel, read nouveau + 4. share intel->nouveau, blit intel fill, readback on nouveau + test 1 + map buffer, read/write, map other size. + do some hw actions on the buffer + some illegal operations - + close prime fd try and map + + TODO add some nouveau rendering tests +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <errno.h> + +#include "i915_drm.h" +#include "intel_bufmgr.h" +#include "nouveau.h" +#include "intel_gpu_tools.h" +#include "intel_batchbuffer.h" + +static int intel_fd = -1, nouveau_fd = -1; +static drm_intel_bufmgr *bufmgr; +static struct nouveau_device *ndev; +static struct nouveau_client *nclient; +static uint32_t devid; +static struct intel_batchbuffer *batch; +static struct nouveau_object *nchannel, *pcopy; +static struct nouveau_bufctx *nbufctx; +static struct nouveau_pushbuf *npush; + +static struct nouveau_bo *query_bo; +static uint32_t query_counter; +static volatile uint32_t *query; +static uint32_t memtype_intel, tile_intel_y, tile_intel_x; + +#define SUBC_COPY(x) 6, (x) +#define NV01_SUBCHAN_OBJECT 0 + +#define NV01_SUBC(subc, mthd) SUBC_##subc((NV01_SUBCHAN_##mthd)) + +#if 0 +#define dbg(fmt...) fprintf(stderr, fmt); +#else +#define dbg(...) do { } while (0) +#endif + +typedef struct { + uint32_t w, h; + uint32_t pitch, lines; +} rect; + +static int nv_bo_alloc(struct nouveau_bo **bo, rect *r, + uint32_t w, uint32_t h, uint32_t tile_mode, + int handle, uint32_t dom) +{ + uint32_t size; + uint32_t dx = 1, dy = 1, memtype = 0; + int ret; + + *bo = NULL; + if (tile_mode) { + uint32_t tile_y; + uint32_t tile_x; + + /* Y major tiling */ + if ((tile_mode & 0xf) == 0xe) + /* but the internal layout is different */ + tile_x = 7; + else + tile_x = 6 + (tile_mode & 0xf); + if (ndev->chipset < 0xc0) { + memtype = 0x70; + tile_y = 2; + } else { + memtype = 0xfe; + tile_y = 3; + } + if ((tile_mode & 0xf) == 0xe) + memtype = memtype_intel; + tile_y += ((tile_mode & 0xf0)>>4); + + dx = 1 << tile_x; + dy = 1 << tile_y; + dbg("Tiling requirements: x y %u %u\n", dx, dy); + } + + r->w = w; + r->h = h; + + r->pitch = w = (w + dx-1) & ~(dx-1); + r->lines = h = (h + dy-1) & ~(dy-1); + size = w*h; + + if (handle < 0) { + union nouveau_bo_config cfg; + cfg.nv50.memtype = memtype; + cfg.nv50.tile_mode = tile_mode; + if (dom == NOUVEAU_BO_GART) + dom |= NOUVEAU_BO_MAP; + ret = nouveau_bo_new(ndev, dom, 4096, size, &cfg, bo); + if (!ret) + ret = nouveau_bo_map(*bo, NOUVEAU_BO_RDWR, nclient); + if (ret) { + fprintf(stderr, "creating bo failed with %i %s\n", + ret, strerror(-ret)); + nouveau_bo_ref(NULL, bo); + return ret; + } + + dbg("new flags %08x memtype %08x tile %08x\n", (*bo)->flags, (*bo)->config.nv50.memtype, (*bo)->config.nv50.tile_mode); + if (tile_mode == tile_intel_y || tile_mode == tile_intel_x) { + dbg("tile mode was: %02x, now: %02x\n", (*bo)->config.nv50.tile_mode, tile_mode); + /* Doesn't like intel tiling much.. */ + (*bo)->config.nv50.tile_mode = tile_mode; + } + } else { + ret = nouveau_bo_prime_handle_ref(ndev, handle, bo); + close(handle); + if (ret < 0) { + fprintf(stderr, "receiving bo failed with %i %s\n", + ret, strerror(-ret)); + return ret; + } + if ((*bo)->size < size) { + fprintf(stderr, "expected bo size to be at least %u," + "but received %"PRIu64"\n", size, (*bo)->size); + nouveau_bo_ref(NULL, bo); + return -1; + } + dbg("prime flags %08x memtype %08x tile %08x\n", (*bo)->flags, (*bo)->config.nv50.memtype, (*bo)->config.nv50.tile_mode); + (*bo)->config.nv50.memtype = memtype; + (*bo)->config.nv50.tile_mode = tile_mode; + } + dbg("size: %"PRIu64"\n", (*bo)->size); + + return ret; +} + +static inline void +PUSH_DATA(struct nouveau_pushbuf *push, uint32_t data) +{ + *push->cur++ = data; +} + +static inline void +BEGIN_NV04(struct nouveau_pushbuf *push, int subc, int mthd, int size) +{ + PUSH_DATA (push, 0x00000000 | (size << 18) | (subc << 13) | mthd); +} + +static inline void +BEGIN_NI04(struct nouveau_pushbuf *push, int subc, int mthd, int size) +{ + PUSH_DATA (push, 0x40000000 | (size << 18) | (subc << 13) | mthd); +} + +static inline void +BEGIN_NVC0(struct nouveau_pushbuf *push, int subc, int mthd, int size) +{ + PUSH_DATA (push, 0x20000000 | (size << 16) | (subc << 13) | (mthd / 4)); +} + +static inline void +BEGIN_NVXX(struct nouveau_pushbuf *push, int subc, int mthd, int size) +{ + if (ndev->chipset < 0xc0) + BEGIN_NV04(push, subc, mthd, size); + else + BEGIN_NVC0(push, subc, mthd, size); +} + +static void +noop_intel(drm_intel_bo *bo) +{ + BEGIN_BATCH(3); + OUT_BATCH(MI_NOOP); + OUT_BATCH(MI_BATCH_BUFFER_END); + OUT_RELOC(bo, I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER, 0); + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); +} + +static int find_and_open_devices(void) +{ + int i; + char path[80], *unused; + struct stat buf; + FILE *fl; + char vendor_id[8] = {}; + int venid; + for (i = 0; i < 9; i++) { + sprintf(path, "/sys/class/drm/card%d/device/vendor", i); + if (stat(path, &buf)) + break; + + fl = fopen(path, "r"); + if (!fl) + break; + + unused = fgets(vendor_id, sizeof(vendor_id)-1, fl); + (void)unused; + fclose(fl); + + venid = strtoul(vendor_id, NULL, 16); + sprintf(path, "/dev/dri/card%d", i); + if (venid == 0x8086) { + intel_fd = open(path, O_RDWR); + if (!intel_fd) + return -1; + } else if (venid == 0x10de) { + nouveau_fd = open(path, O_RDWR); + if (!nouveau_fd) + return -1; + } + } + return 0; +} + +static int init_nouveau(void) +{ + struct nv04_fifo nv04_data = { .vram = 0xbeef0201, + .gart = 0xbeef0202 }; + struct nvc0_fifo nvc0_data = { }; + struct nouveau_fifo *fifo; + int size, ret; + uint32_t class; + void *data; + + ret = nouveau_device_wrap(nouveau_fd, 0, &ndev); + if (ret < 0) { + fprintf(stderr,"failed to wrap nouveau device\n"); + return ret; + } + + ret = nouveau_client_new(ndev, &nclient); + if (ret < 0) { + fprintf(stderr,"failed to setup nouveau client\n"); + return ret; + } + + if (ndev->chipset < 0xa3 || ndev->chipset == 0xaa || ndev->chipset == 0xac) { + fprintf(stderr, "Your card doesn't support PCOPY\n"); + return -1; + } + + // TODO: Get a kepler and add support for it + if (ndev->chipset >= 0xe0) { + fprintf(stderr, "Unsure how kepler works!\n"); + return -1; + } + ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, + 4096, 4096, NULL, &query_bo); + if (!ret) + ret = nouveau_bo_map(query_bo, NOUVEAU_BO_RDWR, nclient); + if (ret < 0) { + fprintf(stderr,"failed to setup query counter\n"); + return ret; + } + query = query_bo->map; + *query = query_counter; + + if (ndev->chipset < 0xc0) { + class = 0x85b5; + data = &nv04_data; + size = sizeof(nv04_data); + } else { + class = ndev->chipset < 0xe0 ? 0x490b5 : 0xa0b5; + data = &nvc0_data; + size = sizeof(nvc0_data); + } + + ret = nouveau_object_new(&ndev->object, 0, NOUVEAU_FIFO_CHANNEL_CLASS, + data, size, &nchannel); + if (ret) { + fprintf(stderr, "Error creating GPU channel: %d\n", ret); + if (ret == -ENODEV) { + fprintf(stderr, "Make sure nouveau_accel is active\n"); + fprintf(stderr, "nvd9 is likely broken regardless\n"); + } + return ret; + } + + fifo = nchannel->data; + + ret = nouveau_pushbuf_new(nclient, nchannel, 4, 32 * 1024, + true, &npush); + if (ret) { + fprintf(stderr, "Error allocating DMA push buffer: %d\n", ret); + return ret; + } + + ret = nouveau_bufctx_new(nclient, 1, &nbufctx); + if (ret) { + fprintf(stderr, "Error allocating buffer context: %d\n", ret); + return ret; + } + + npush->user_priv = nbufctx; + + /* Hope this is enough init for PCOPY */ + ret = nouveau_object_new(nchannel, class, class & 0xffff, NULL, 0, &pcopy); + if (ret) { + fprintf(stderr, "Failed to allocate pcopy: %d\n", ret); + return ret; + } + ret = nouveau_pushbuf_space(npush, 512, 0, 0); + if (ret) { + fprintf(stderr, "No space in pushbuf: %d\n", ret); + return ret; + } + if (ndev->chipset < 0xc0) { + struct nv04_fifo *nv04_fifo = (struct nv04_fifo*)fifo; + tile_intel_y = 0x3e; + tile_intel_x = 0x13; + + BEGIN_NV04(npush, NV01_SUBC(COPY, OBJECT), 1); + PUSH_DATA(npush, pcopy->handle); + BEGIN_NV04(npush, SUBC_COPY(0x0180), 3); + PUSH_DATA(npush, nv04_fifo->vram); + PUSH_DATA(npush, nv04_fifo->vram); + PUSH_DATA(npush, nv04_fifo->vram); + } else { + tile_intel_y = 0x2e; + tile_intel_x = 0x03; + BEGIN_NVC0(npush, NV01_SUBC(COPY, OBJECT), 1); + PUSH_DATA(npush, pcopy->handle); + } + nouveau_pushbuf_kick(npush, npush->channel); + return ret; +} + +static void fill16(void *ptr, uint32_t val) +{ + uint32_t *p = ptr; + val = (val) | (val << 8) | (val << 16) | (val << 24); + p[0] = p[1] = p[2] = p[3] = val; +} + +#define TILE_SIZE 4096 + +static int swtile_y(uint8_t *out, const uint8_t *in, int w, int h) +{ + uint32_t x, y, dx, dy; + uint8_t *endptr = out + w * h; + assert(!(w % 128)); + assert(!(h % 32)); + + for (y = 0; y < h; y += 32) { + for (x = 0; x < w; x += 128, out += TILE_SIZE) { + for (dx = 0; dx < 8; ++dx) { + for (dy = 0; dy < 32; ++dy) { + uint32_t out_ofs = (dx * 32 + dy) * 16; + uint32_t in_ofs = (y + dy) * w + (x + 16 * dx); + assert(out_ofs < TILE_SIZE); + assert(in_ofs < w*h); + + // To do the Y tiling quirk: + // out_ofs = out_ofs ^ (((out_ofs >> 9) & 1) << 6); + memcpy(&out[out_ofs], &in[in_ofs], 16); + } + } + } + } + assert(out == endptr); + return 0; +} + +static int swtile_x(uint8_t *out, const uint8_t *in, int w, int h) +{ + uint32_t x, y, dy; + uint8_t *endptr = out + w * h; + assert(!(w % 512)); + assert(!(h % 8)); + + for (y = 0; y < h; y += 8) { + for (x = 0; x < w; x += 512, out += TILE_SIZE) { + for (dy = 0; dy < 8; ++dy) { + uint32_t out_ofs = 512 * dy; + uint32_t in_ofs = (y + dy) * w + x; + assert(out_ofs < TILE_SIZE); + assert(in_ofs < w*h); + memcpy(&out[out_ofs], &in[in_ofs], 512); + } + } + } + assert(out == endptr); + return 0; +} + +#if 0 +/* X tiling is approximately linear, except tiled in 512x8 blocks, so lets abuse that + * + * How? Whole contiguous tiles can be copied safely as if linear + */ + +static int perform_copy_hack(struct nouveau_bo *nvbo, const rect *dst, + uint32_t dst_x, uint32_t dst_y, + struct nouveau_bo *nvbi, const rect *src, + uint32_t src_x, uint32_t src_y, + uint32_t w, uint32_t h) +{ + struct nouveau_pushbuf_refn refs[] = { + { nvbi, (nvbi->flags & NOUVEAU_BO_APER) | NOUVEAU_BO_RD }, + { nvbo, (nvbo->flags & NOUVEAU_BO_APER) | NOUVEAU_BO_WR }, + { query_bo, NOUVEAU_BO_GART | NOUVEAU_BO_RDWR } + }; + uint32_t exec = 0x00000000; + uint32_t src_off = 0, dst_off = 0; + struct nouveau_pushbuf *push = npush; + uint32_t dw, tiles, tile_src = nvbi->config.nv50.tile_mode, tile_dst = nvbo->config.nv50.tile_mode; + + if (tile_src == tile_intel_x) + dw = 512 - (src_x & 512); + else + dw = 512 - (dst_x % 512); + + if (!nvbi->config.nv50.memtype) + exec |= 0x00000010; + if (!tile_src) + src_off = src_y * src->pitch + src_x; + + if (!nvbo->config.nv50.memtype) + exec |= 0x00000100; + if (!tile_dst) + dst_off = dst_y * dst->pitch + dst_x; + + if (dw > w) + dw = w; + tiles = 1 + ((w - dw + 511)/512); + + if (nouveau_pushbuf_space(push, 8 + tiles * 32, 0, 0) || + nouveau_pushbuf_refn(push, refs, 3)) + return -1; + + for (; w; w -= dw, src_x += dw, dst_x += dw, dw = w > 512 ? 512 : w) { + if (tile_src == tile_intel_x) { + /* Find the correct tiled offset */ + src_off = 8 * dst->pitch * (src_y / 8); + src_off += src_x / 512 * 4096; + src_off += (src_x % 512) + 512 * (src_y % 8); + + if (!tile_dst) + dst_off = dst_y * dst->pitch + dst_x; + } else { + if (!tile_src) + src_off = src_y * src->pitch + src_x; + + dst_off = 8 * dst->pitch * (dst_y / 8); + dst_off += dst_x / 512 * 4096; + dst_off += (dst_x % 512) + 512 * (dst_y % 8); + } + + fprintf(stderr, "Copying from %u to %u for %u bytes\n", src_x, dst_x, dw); + fprintf(stderr, "src ofs: %u, dst ofs: %u\n", src_off, dst_off); + BEGIN_NVXX(push, SUBC_COPY(0x0200), 7); + PUSH_DATA (push, tile_src == tile_intel_x ? 0 : nvbi->config.nv50.tile_mode); + PUSH_DATA (push, src->pitch); + PUSH_DATA (push, src->h); + PUSH_DATA (push, 1); + PUSH_DATA (push, 0); + PUSH_DATA (push, src_x); + PUSH_DATA (push, src_y); + + BEGIN_NVXX(push, SUBC_COPY(0x0220), 7); + PUSH_DATA (push, tile_dst == tile_intel_x ? 0 : nvbo->config.nv50.tile_mode); + PUSH_DATA (push, dst->pitch); + PUSH_DATA (push, dst->h); + PUSH_DATA (push, 1); + PUSH_DATA (push, 0); + PUSH_DATA (push, dst_x); + PUSH_DATA (push, dst_y); + + BEGIN_NVXX(push, SUBC_COPY(0x030c), 8); + PUSH_DATA (push, (nvbi->offset + src_off) >> 32); + PUSH_DATA (push, (nvbi->offset + src_off)); + PUSH_DATA (push, (nvbo->offset + dst_off) >> 32); + PUSH_DATA (push, (nvbo->offset + dst_off)); + PUSH_DATA (push, src->pitch); + PUSH_DATA (push, dst->pitch); + PUSH_DATA (push, dw); + PUSH_DATA (push, h); + + if (w == dw) { + exec |= 0x3000; /* QUERY|QUERY_SHORT */ + BEGIN_NVXX(push, SUBC_COPY(0x0338), 3); + PUSH_DATA (push, (query_bo->offset) >> 32); + PUSH_DATA (push, (query_bo->offset)); + PUSH_DATA (push, ++query_counter); + } + + BEGIN_NVXX(push, SUBC_COPY(0x0300), 1); + PUSH_DATA (push, exec); + } + nouveau_pushbuf_kick(push, push->channel); + while (*query < query_counter) { } + return 0; +} +#endif + +static int perform_copy(struct nouveau_bo *nvbo, const rect *dst, + uint32_t dst_x, uint32_t dst_y, + struct nouveau_bo *nvbi, const rect *src, + uint32_t src_x, uint32_t src_y, + uint32_t w, uint32_t h) +{ +#if 0 + /* Too much effort */ + if (nvbi->config.nv50.tile_mode == tile_intel_x && + nvbo->config.nv50.tile_mode == tile_intel_x) + return -1; + else if (nvbi->config.nv50.tile_mode == tile_intel_x || + nvbo->config.nv50.tile_mode == tile_intel_x) + return perform_copy_hack(nvbo, dst, dst_x, dst_y, + nvbi, src, src_x, src_y, w, h); +#endif + struct nouveau_pushbuf_refn refs[] = { + { nvbi, (nvbi->flags & NOUVEAU_BO_APER) | NOUVEAU_BO_RD }, + { nvbo, (nvbo->flags & NOUVEAU_BO_APER) | NOUVEAU_BO_WR }, + { query_bo, NOUVEAU_BO_GART | NOUVEAU_BO_RDWR } + }; + uint32_t cpp = 1, exec = 0x00003000; /* QUERY|QUERY_SHORT|FORMAT */ + uint32_t src_off = 0, dst_off = 0; + struct nouveau_pushbuf *push = npush; + + if (nvbi->config.nv50.tile_mode == tile_intel_y) + dbg("src is y-tiled\n"); + if (nvbo->config.nv50.tile_mode == tile_intel_y) + dbg("dst is y-tiled\n"); + + if (nouveau_pushbuf_space(push, 64, 0, 0) || + nouveau_pushbuf_refn(push, refs, 3)) + return -1; + + if (!nvbi->config.nv50.tile_mode) { + src_off = src_y * src->pitch + src_x; + exec |= 0x00000010; + } + + if (!nvbo->config.nv50.tile_mode) { + dst_off = dst_y * dst->pitch + dst_x; + exec |= 0x00000100; + } + + BEGIN_NVXX(push, SUBC_COPY(0x0200), 7); + PUSH_DATA (push, nvbi->config.nv50.tile_mode); + PUSH_DATA (push, src->pitch / cpp); + PUSH_DATA (push, src->h); + PUSH_DATA (push, 1); + PUSH_DATA (push, 0); + PUSH_DATA (push, src_x / cpp); + PUSH_DATA (push, src_y); + + BEGIN_NVXX(push, SUBC_COPY(0x0220), 7); + PUSH_DATA (push, nvbo->config.nv50.tile_mode); + PUSH_DATA (push, dst->pitch / cpp); + PUSH_DATA (push, dst->h); + PUSH_DATA (push, 1); + PUSH_DATA (push, 0); + PUSH_DATA (push, dst_x / cpp); + PUSH_DATA (push, dst_y); + + BEGIN_NVXX(push, SUBC_COPY(0x030c), 9); + PUSH_DATA (push, (nvbi->offset + src_off) >> 32); + PUSH_DATA (push, (nvbi->offset + src_off)); + PUSH_DATA (push, (nvbo->offset + dst_off) >> 32); + PUSH_DATA (push, (nvbo->offset + dst_off)); + PUSH_DATA (push, src->pitch); + PUSH_DATA (push, dst->pitch); + PUSH_DATA (push, w / cpp); + PUSH_DATA (push, h); + PUSH_DATA (push, 0x03333120); + + BEGIN_NVXX(push, SUBC_COPY(0x0338), 3); + PUSH_DATA (push, (query_bo->offset) >> 32); + PUSH_DATA (push, (query_bo->offset)); + PUSH_DATA (push, ++query_counter); + + BEGIN_NVXX(push, SUBC_COPY(0x0300), 1); + PUSH_DATA (push, exec); + + nouveau_pushbuf_kick(push, push->channel); + while (*query < query_counter) { usleep(1000); } + return 0; +} + +static int check1_macro(uint32_t *p, uint32_t w, uint32_t h) +{ + uint32_t i, val, j; + + for (i = 0; i < 256; ++i, p += 4) { + val = (i) | (i << 8) | (i << 16) | (i << 24); + if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) { + fprintf(stderr, "Retile check failed in first tile!\n"); + fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n", + p[0], p[1], p[2], p[3], val); + return -1; + } + } + + val = 0x3e3e3e3e; + for (i = 0; i < 256 * (w-1); ++i, p += 4) { + if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) { + fprintf(stderr, "Retile check failed in second tile!\n"); + fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n", + p[0], p[1], p[2], p[3], val); + return -1; + } + } + + for (j = 1; j < h; ++j) { + val = 0x7e7e7e7e; + for (i = 0; i < 256; ++i, p += 4) { + if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) { + fprintf(stderr, "Retile check failed in third tile!\n"); + fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n", + p[0], p[1], p[2], p[3], val); + return -1; + } + } + + val = 0xcececece; + for (i = 0; i < 256 * (w-1); ++i, p += 4) { + if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) { + fprintf(stderr, "Retile check failed in fourth tile!\n"); + fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n", + p[0], p[1], p[2], p[3], val); + return -1; + } + } + } + return 0; +} + +/* test 1, see if we can copy from linear to intel Y format safely */ +static int test1_macro(void) +{ + int ret, prime_fd = -1; + struct nouveau_bo *nvbo = NULL, *nvbi = NULL; + rect dst, src; + uint8_t *ptr; + uint32_t w = 2 * 128, h = 2 * 32, x, y; + + ret = nv_bo_alloc(&nvbi, &src, w, h, 0, -1, NOUVEAU_BO_GART); + if (ret >= 0) + ret = nv_bo_alloc(&nvbo, &dst, w, h, tile_intel_y, -1, NOUVEAU_BO_GART); + if (ret < 0) + goto out; + + nouveau_bo_set_prime(nvbo, &prime_fd); + + /* Set up something for our tile that should map into the first + * y-major tile, assuming my understanding of documentation is + * correct + */ + + /* First tile should be read out in groups of 16 bytes that + * are all set to a linear increasing value.. + */ + ptr = nvbi->map; + for (x = 0; x < 128; x += 16) + for (y = 0; y < 32; ++y) + fill16(&ptr[y * w + x], x * 2 + y); + + /* second tile */ + for (x = 128; x < w; x += 16) + for (y = 0; y < 32; ++y) + fill16(&ptr[y * w + x], 0x3e); + + /* third tile */ + for (x = 0; x < 128; x += 16) + for (y = 32; y < h; ++y) + fill16(&ptr[y * w + x], 0x7e); + + /* last tile */ + for (x = 128; x < w; x += 16) + for (y = 32; y < h; ++y) + fill16(&ptr[y * w + x], 0xce); + memset(nvbo->map, 0xfc, w * h); + + if (pcopy) + ret = perform_copy(nvbo, &dst, 0, 0, nvbi, &src, 0, 0, w, h); + else + ret = swtile_y(nvbo->map, nvbi->map, w, h); + if (!ret) + ret = check1_macro(nvbo->map, w/128, h/32); + +out: + nouveau_bo_ref(NULL, &nvbo); + nouveau_bo_ref(NULL, &nvbi); + close(prime_fd); + return ret; +} + +static int dump_line(uint8_t *map) +{ + uint32_t dx, dy; + fprintf(stderr, "Dumping sub-tile:\n"); + for (dy = 0; dy < 32; ++dy) { + for (dx = 0; dx < 15; ++dx, ++map) { + fprintf(stderr, "%02x ", *map); + } + fprintf(stderr, "%02x\n", *(map++)); + } + return -1; +} + +static int check1_micro(void *map, uint32_t pitch, uint32_t lines, + uint32_t dst_x, uint32_t dst_y, uint32_t w, uint32_t h) +{ + uint32_t x, y; + + /* check only the relevant subrectangle [0..w) [0...h) */ + uint8_t *m = map; + for (y = 0; y < h; ++y, m += pitch) { + for (x = 0; x < w; ++x) { + uint8_t expected = ((y & 3) << 6) | (x & 0x3f); + if (expected != m[x]) { + fprintf(stderr, "failed check at x=%u y=%u, expected %02x got %02x\n", + x, y, expected, m[x]); + return dump_line(m); + } + } + } + + return 0; +} + +/* test 1, but check micro format, should be unaffected by bit9 swizzling */ +static int test1_micro(void) +{ + struct nouveau_bo *bo_intel = NULL, *bo_nvidia = NULL, *bo_linear = NULL; + rect intel, nvidia, linear; + int ret = -1; + uint32_t tiling = I915_TILING_Y; + + uint32_t src_x = 0, src_y = 0; + uint32_t dst_x = 0, dst_y = 0; + uint32_t x, y, w = 256, h = 64; + + drm_intel_bo *test_intel_bo; + int prime_fd; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", w * h, 4096); + if (!test_intel_bo) + return -1; + drm_intel_bo_set_tiling(test_intel_bo, &tiling, w); + if (tiling != I915_TILING_Y) { + fprintf(stderr, "Couldn't set y tiling\n"); + goto out; + } + ret = drm_intel_gem_bo_map_gtt(test_intel_bo); + if (ret) + goto out; + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + if (prime_fd < 0) { + drm_intel_bo_unreference(test_intel_bo); + goto out; + } + noop_intel(test_intel_bo); + + ret = nv_bo_alloc(&bo_intel, &intel, w, h, tile_intel_y, prime_fd, 0); + if (!ret) + ret = nv_bo_alloc(&bo_nvidia, &nvidia, w, h, 0x10, -1, NOUVEAU_BO_VRAM); + if (!ret) + ret = nv_bo_alloc(&bo_linear, &linear, w, h, 0, -1, NOUVEAU_BO_GART); + if (ret) + goto out; + + for (y = 0; y < linear.h; ++y) { + uint8_t *map = bo_linear->map; + map += y * linear.pitch; + for (x = 0; x < linear.pitch; ++x) { + uint8_t pos = x & 0x3f; + /* low 4 bits: micro tile pos */ + /* 2 bits: x pos in tile (wraps) */ + /* 2 bits: y pos in tile (wraps) */ + pos |= (y & 3) << 6; + map[x] = pos; + } + } + + ret = perform_copy(bo_nvidia, &nvidia, 0, 0, bo_linear, &linear, 0, 0, nvidia.pitch, nvidia.h); + if (ret) + goto out; + + /* Perform the actual sub rectangle copy */ + if (pcopy) + ret = perform_copy(bo_intel, &intel, dst_x, dst_y, bo_nvidia, &nvidia, src_x, src_y, w, h); + else + ret = swtile_y(test_intel_bo->virtual, bo_linear->map, w, h); + if (ret) + goto out; + + noop_intel(test_intel_bo); + ret = check1_micro(test_intel_bo->virtual, intel.pitch, intel.h, dst_x, dst_y, w, h); + +out: + nouveau_bo_ref(NULL, &bo_linear); + nouveau_bo_ref(NULL, &bo_nvidia); + nouveau_bo_ref(NULL, &bo_intel); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +static int check1_swizzle(uint32_t *p, uint32_t pitch, uint32_t lines, + uint32_t dst_x, uint32_t dst_y, uint32_t w, uint32_t h) +{ + uint32_t i, val, j; + + for (j = 0; j < 32; ++j, p += (pitch - w)/4) { + for (i = 0; i < 8; ++i, p += 4) { + val = (i * 32) + j; + val = (val) | (val << 8) | (val << 16) | (val << 24); + if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) { + fprintf(stderr, "Retile check failed in first tile!\n"); + fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n", + p[0], p[1], p[2], p[3], val); + return -1; + } + } + + val = 0x3e3e3e3e; + for (; i < w/16; ++i, p += 4) { + if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) { + fprintf(stderr, "Retile check failed in second tile!\n"); + fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n", + p[0], p[1], p[2], p[3], val); + return -1; + } + } + } + + for (j = 32; j < h; ++j, p += (pitch - w)/4) { + val = 0x7e7e7e7e; + for (i = 0; i < 8; ++i, p += 4) { + if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) { + fprintf(stderr, "Retile check failed in third tile!\n"); + fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n", + p[0], p[1], p[2], p[3], val); + return -1; + } + } + + val = 0xcececece; + for (; i < w/16; ++i, p += 4) { + if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) { + fprintf(stderr, "Retile check failed in fourth tile!\n"); + fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n", + p[0], p[1], p[2], p[3], val); + return -1; + } + } + } + return 0; +} + +/* Create a new bo, set tiling to y, and see if macro swizzling is done correctl */ +static int test1_swizzle(void) +{ + struct nouveau_bo *bo_intel = NULL, *bo_nvidia = NULL, *bo_linear = NULL; + rect intel, nvidia, linear; + int ret = -1; + uint32_t tiling = I915_TILING_Y; + + uint32_t src_x = 0, src_y = 0; + uint32_t dst_x = 0, dst_y = 0; + uint32_t x, y, w = 256, h = 64; + uint8_t *ptr; + + drm_intel_bo *test_intel_bo; + int prime_fd; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", w * h, 4096); + if (!test_intel_bo) + return -1; + drm_intel_bo_set_tiling(test_intel_bo, &tiling, w); + if (tiling != I915_TILING_Y) { + fprintf(stderr, "Couldn't set y tiling\n"); + goto out; + } + ret = drm_intel_gem_bo_map_gtt(test_intel_bo); + if (ret) + goto out; + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + if (prime_fd < 0) { + drm_intel_bo_unreference(test_intel_bo); + goto out; + } + + ret = nv_bo_alloc(&bo_intel, &intel, w, h, tile_intel_y, prime_fd, 0); + if (!ret) + ret = nv_bo_alloc(&bo_nvidia, &nvidia, w, h, 0x10, -1, NOUVEAU_BO_VRAM); + if (!ret) + ret = nv_bo_alloc(&bo_linear, &linear, w, h, 0, -1, NOUVEAU_BO_GART); + if (ret) + goto out; + + noop_intel(test_intel_bo); + ptr = bo_linear->map; + for (x = 0; x < 128; x += 16) + for (y = 0; y < 32; ++y) + fill16(&ptr[y * w + x], x * 2 + y); + + /* second tile */ + for (x = 128; x < w; x += 16) + for (y = 0; y < 32; ++y) + fill16(&ptr[y * w + x], 0x3e); + + /* third tile */ + for (x = 0; x < 128; x += 16) + for (y = 32; y < h; ++y) + fill16(&ptr[y * w + x], 0x7e); + + /* last tile */ + for (x = 128; x < w; x += 16) + for (y = 32; y < h; ++y) + fill16(&ptr[y * w + x], 0xce); + + ret = perform_copy(bo_nvidia, &nvidia, 0, 0, bo_linear, &linear, 0, 0, nvidia.pitch, nvidia.h); + if (ret) + goto out; + + /* Perform the actual sub rectangle copy */ + ret = perform_copy(bo_intel, &intel, dst_x, dst_y, bo_nvidia, &nvidia, src_x, src_y, w, h); + if (ret) + goto out; + noop_intel(test_intel_bo); + + ret = check1_swizzle(test_intel_bo->virtual, intel.pitch, intel.h, dst_x, dst_y, w, h); + +out: + nouveau_bo_ref(NULL, &bo_linear); + nouveau_bo_ref(NULL, &bo_nvidia); + nouveau_bo_ref(NULL, &bo_intel); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +/* test 2, see if we can copy from linear to intel X format safely + * Seems nvidia lacks a method to do it, so just keep this test + * as a reference for potential future tests. Software tiling is + * used for now + */ +static int test2(void) +{ + int ret; + struct nouveau_bo *nvbo = NULL, *nvbi = NULL; + rect dst, src; + uint8_t *ptr; + uint32_t w = 1024, h = 16, x, y; + + ret = nv_bo_alloc(&nvbi, &src, w, h, 0, -1, NOUVEAU_BO_GART); + if (ret >= 0) + ret = nv_bo_alloc(&nvbo, &dst, w, h, tile_intel_x, -1, NOUVEAU_BO_GART); + if (ret < 0) + goto out; + + /* Set up something for our tile that should map into the first + * y-major tile, assuming my understanding of documentation is + * correct + */ + + /* First tile should be read out in groups of 16 bytes that + * are all set to a linear increasing value.. + */ + ptr = nvbi->map; + for (y = 0; y < 8; ++y) + for (x = 0; x < 512; x += 16) + fill16(&ptr[y * w + x], (y * 512 + x)/16); + + for (y = 0; y < 8; ++y) + for (x = 512; x < w; x += 16) + fill16(&ptr[y * w + x], 0x3e); + + for (y = 8; y < h; ++y) + for (x = 0; x < 512; x += 16) + fill16(&ptr[y * w + x], 0x7e); + + for (y = 8; y < h; ++y) + for (x = 512; x < w; x += 16) + fill16(&ptr[y * w + x], 0xce); + memset(nvbo->map, 0xfc, w * h); + + /* do this in software, there is no X major tiling in PCOPY (yet?) */ + if (0 && pcopy) + ret = perform_copy(nvbo, &dst, 0, 0, nvbi, &src, 0, 0, w, h); + else + ret = swtile_x(nvbo->map, nvbi->map, w, h); + if (!ret) + ret = check1_macro(nvbo->map, w/512, h/8); + +out: + nouveau_bo_ref(NULL, &nvbo); + nouveau_bo_ref(NULL, &nvbi); + return ret; +} + +static int check3(const uint32_t *p, uint32_t pitch, uint32_t lines, + uint32_t sub_x, uint32_t sub_y, + uint32_t sub_w, uint32_t sub_h) +{ + uint32_t x, y; + + sub_w += sub_x; + sub_h += sub_y; + + if (p[pitch * lines / 4 - 1] == 0x03030303) { + fprintf(stderr, "copy failed: Not all lines have been copied back!\n"); + return -1; + } + + for (y = 0; y < lines; ++y) { + for (x = 0; x < pitch; x += 4, ++p) { + uint32_t expected; + if ((x < sub_x || x >= sub_w) || + (y < sub_y || y >= sub_h)) + expected = 0x80808080; + else + expected = 0x04040404; + if (*p != expected) { + fprintf(stderr, "%u,%u should be %08x, but is %08x\n", x, y, expected, *p); + return -1; + } + } + } + return 0; +} + +/* copy from nvidia bo to intel bo and copy to a linear bo to check if tiling went succesful */ +static int test3_base(int tile_src, int tile_dst) +{ + struct nouveau_bo *bo_intel = NULL, *bo_nvidia = NULL, *bo_linear = NULL; + rect intel, nvidia, linear; + int ret; + uint32_t cpp = 4; + + uint32_t src_x = 1 * cpp, src_y = 1; + uint32_t dst_x = 2 * cpp, dst_y = 26; + uint32_t w = 298 * cpp, h = 298; + + drm_intel_bo *test_intel_bo; + int prime_fd; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", 2048 * cpp * 768, 4096); + if (!test_intel_bo) + return -1; + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + if (prime_fd < 0) { + drm_intel_bo_unreference(test_intel_bo); + return -1; + } + + ret = nv_bo_alloc(&bo_intel, &intel, 2048 * cpp, 768, tile_dst, prime_fd, 0); + if (!ret) + ret = nv_bo_alloc(&bo_nvidia, &nvidia, 300 * cpp, 300, tile_src, -1, NOUVEAU_BO_VRAM); + if (!ret) + ret = nv_bo_alloc(&bo_linear, &linear, 2048 * cpp, 768, 0, -1, NOUVEAU_BO_GART); + if (ret) + goto out; + + noop_intel(test_intel_bo); + memset(bo_linear->map, 0x80, bo_linear->size); + ret = perform_copy(bo_intel, &intel, 0, 0, bo_linear, &linear, 0, 0, linear.pitch, linear.h); + if (ret) + goto out; + noop_intel(test_intel_bo); + + memset(bo_linear->map, 0x04, bo_linear->size); + ret = perform_copy(bo_nvidia, &nvidia, 0, 0, bo_linear, &linear, 0, 0, nvidia.pitch, nvidia.h); + if (ret) + goto out; + + /* Perform the actual sub rectangle copy */ + noop_intel(test_intel_bo); + ret = perform_copy(bo_intel, &intel, dst_x, dst_y, bo_nvidia, &nvidia, src_x, src_y, w, h); + if (ret) + goto out; + noop_intel(test_intel_bo); + + memset(bo_linear->map, 0x3, bo_linear->size); + noop_intel(test_intel_bo); + ret = perform_copy(bo_linear, &linear, 0, 0, bo_intel, &intel, 0, 0, intel.pitch, intel.h); + if (ret) + goto out; + noop_intel(test_intel_bo); + + ret = check3(bo_linear->map, linear.pitch, linear.h, dst_x, dst_y, w, h); + +out: + nouveau_bo_ref(NULL, &bo_linear); + nouveau_bo_ref(NULL, &bo_nvidia); + nouveau_bo_ref(NULL, &bo_intel); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +static int test3_1(void) +{ + /* nvidia tiling to intel */ + return test3_base(0x40, tile_intel_y); +} + +static int test3_2(void) +{ + /* intel tiling to nvidia */ + return test3_base(tile_intel_y, 0x40); +} + +static int test3_3(void) +{ + /* intel tiling to linear */ + return test3_base(tile_intel_y, 0); +} + +static int test3_4(void) +{ + /* linear tiling to intel */ + return test3_base(0, tile_intel_y); +} + +static int test3_5(void) +{ + /* linear to linear */ + return test3_base(0, 0); +} + +/* Acquire when == SEQUENCE */ +#define SEMA_ACQUIRE_EQUAL 1 + +/* Release, and write a 16 byte query structure to sema: + * { (uint32)seq, (uint32)0, (uint64)timestamp } */ +#define SEMA_WRITE_LONG 2 + +/* Acquire when >= SEQUENCE */ +#define SEMA_ACQUIRE_GEQUAL 4 + +/* Test only new style semaphores, old ones are AWFUL */ +static int test_semaphore(void) +{ + drm_intel_bo *test_intel_bo = NULL; + struct nouveau_bo *sema_bo = NULL; + int ret = -1, prime_fd; + uint32_t *sema; + struct nouveau_pushbuf *push = npush; + + if (ndev->chipset < 0x84) + return -1; + + /* Should probably be kept in sysmem */ + test_intel_bo = drm_intel_bo_alloc(bufmgr, "semaphore bo", 4096, 4096); + if (!test_intel_bo) + goto out; + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + if (prime_fd < 0) + goto out; + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &sema_bo); + close(prime_fd); + if (ret < 0) + goto out; + + ret = drm_intel_gem_bo_map_gtt(test_intel_bo); + if (ret != 0) { + fprintf(stderr,"failed to map bo\n"); + goto out; + } + sema = test_intel_bo->virtual; + sema++; + *sema = 0; + + ret = -1; + if (nouveau_pushbuf_space(push, 64, 0, 0) || + nouveau_pushbuf_refn(push, &(struct nouveau_pushbuf_refn) + { sema_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR }, 1)) + goto out; + + if (ndev->chipset < 0xc0) { + struct nv04_fifo *nv04_fifo = nchannel->data; + /* kernel binds it's own dma object here and overwrites old one, + * so just rebind vram every time we submit + */ + BEGIN_NV04(npush, SUBC_COPY(0x0060), 1); + PUSH_DATA(npush, nv04_fifo->vram); + } + BEGIN_NVXX(push, SUBC_COPY(0x0010), 4); + PUSH_DATA(push, sema_bo->offset >> 32); + PUSH_DATA(push, sema_bo->offset + 4); + PUSH_DATA(push, 2); // SEQUENCE + PUSH_DATA(push, SEMA_WRITE_LONG); // TRIGGER + + BEGIN_NVXX(push, SUBC_COPY(0x0018), 2); + PUSH_DATA(push, 3); + PUSH_DATA(push, SEMA_ACQUIRE_EQUAL); + BEGIN_NVXX(push, SUBC_COPY(0x0018), 2); + PUSH_DATA(push, 4); + PUSH_DATA(push, SEMA_WRITE_LONG); + + BEGIN_NVXX(push, SUBC_COPY(0x0018), 2); + PUSH_DATA(push, 5); + PUSH_DATA(push, SEMA_ACQUIRE_GEQUAL); + BEGIN_NVXX(push, SUBC_COPY(0x0018), 2); + PUSH_DATA(push, 6); + PUSH_DATA(push, SEMA_WRITE_LONG); + + BEGIN_NVXX(push, SUBC_COPY(0x0018), 2); + PUSH_DATA(push, 7); + PUSH_DATA(push, SEMA_ACQUIRE_GEQUAL); + BEGIN_NVXX(push, SUBC_COPY(0x0018), 2); + PUSH_DATA(push, 9); + PUSH_DATA(push, SEMA_WRITE_LONG); + nouveau_pushbuf_kick(push, push->channel); + + usleep(1000); + if (*sema != 2) { + fprintf(stderr, "new sema should be 2 is %u\n", *sema); + goto out; + } + + *sema = 3; + usleep(1000); + if (*sema != 4) { + fprintf(stderr, "new sema should be 4 is %u\n", *sema); + goto out; + } + + *sema = 5; + usleep(1000); + if (*sema != 6) { + fprintf(stderr, "new sema should be 6 is %u\n", *sema); + goto out; + } + + *sema = 8; + usleep(1000); + if (*sema != 9) { + fprintf(stderr, "new sema should be 9 is %u\n", *sema); + goto out; + } + ret = 0; + +out: + nouveau_bo_ref(NULL, &sema_bo); + if (test_intel_bo) + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +int main(int argc, char **argv) +{ + int ret, failed = 0, run = 0; + + ret = find_and_open_devices(); + if (ret < 0) + return ret; + + if (nouveau_fd == -1 || intel_fd == -1) { + fprintf(stderr,"failed to find intel and nouveau GPU\n"); + return 77; + } + + /* set up intel bufmgr */ + bufmgr = drm_intel_bufmgr_gem_init(intel_fd, 4096); + if (!bufmgr) + return -1; + /* Do not enable reuse, we share (almost) all buffers. */ + //drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + /* set up nouveau bufmgr */ + ret = init_nouveau(); + if (ret < 0) + return 77; + + /* set up an intel batch buffer */ + devid = intel_get_drm_devid(intel_fd); + batch = intel_batchbuffer_alloc(bufmgr, devid); + +#define xtest(x, args...) do { \ + ret = ((x)(args)); \ + ++run; \ + if (ret) { \ + ++failed; \ + fprintf(stderr, "prime_pcopy: failed " #x "\n"); } \ + } while (0) + + xtest(test1_macro); + xtest(test1_micro); + xtest(test1_swizzle); + xtest(test2); + xtest(test3_1); + xtest(test3_2); + xtest(test3_3); + xtest(test3_4); + xtest(test3_5); + xtest(test_semaphore); + + nouveau_bo_ref(NULL, &query_bo); + nouveau_object_del(&pcopy); + nouveau_bufctx_del(&nbufctx); + nouveau_pushbuf_del(&npush); + nouveau_object_del(&nchannel); + + intel_batchbuffer_free(batch); + + nouveau_client_del(&nclient); + nouveau_device_del(&ndev); + drm_intel_bufmgr_destroy(bufmgr); + + close(intel_fd); + close(nouveau_fd); + + printf("Tests: %u run, %u failed\n", run, failed); + return failed; +} diff --git a/tests/prime_nv_test.c b/tests/prime_nv_test.c new file mode 100644 index 00000000..2269f84f --- /dev/null +++ b/tests/prime_nv_test.c @@ -0,0 +1,582 @@ +/* basic set of prime tests between intel and nouveau */ + +/* test list - + 1. share buffer from intel -> nouveau. + 2. share buffer from nouveau -> intel + 3. share intel->nouveau, map on both, write intel, read nouveau + 4. share intel->nouveau, blit intel fill, readback on nouveau + test 1 + map buffer, read/write, map other size. + do some hw actions on the buffer + some illegal operations - + close prime fd try and map + + TODO add some nouveau rendering tests +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include "i915_drm.h" +#include "intel_bufmgr.h" +#include "nouveau.h" +#include "intel_gpu_tools.h" +#include "intel_batchbuffer.h" + +int intel_fd = -1, nouveau_fd = -1; +drm_intel_bufmgr *bufmgr; +struct nouveau_device *ndev; +struct nouveau_client *nclient; +uint32_t devid; +struct intel_batchbuffer *intel_batch; + +#define BO_SIZE (256*1024) + +static int find_and_open_devices(void) +{ + int i; + char path[80]; + struct stat buf; + FILE *fl; + char vendor_id[8]; + int venid; + for (i = 0; i < 9; i++) { + sprintf(path, "/sys/class/drm/card%d/device/vendor", i); + if (stat(path, &buf)) + break; + + fl = fopen(path, "r"); + if (!fl) + break; + + fgets(vendor_id, 8, fl); + fclose(fl); + + venid = strtoul(vendor_id, NULL, 16); + sprintf(path, "/dev/dri/card%d", i); + if (venid == 0x8086) { + intel_fd = open(path, O_RDWR); + if (!intel_fd) + return -1; + } else if (venid == 0x10de) { + nouveau_fd = open(path, O_RDWR); + if (!nouveau_fd) + return -1; + } + } + return 0; +} + +/* + * prime test 1 - + * allocate buffer on intel, + * set prime on buffer, + * retrive buffer from nouveau, + * close prime_fd, + * unref buffers + */ +static int test1(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd; + struct nouveau_bo *nvbo; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096); + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo); + close(prime_fd); + if (ret < 0) + return ret; + + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return 0; +} + +/* + * prime test 2 - + * allocate buffer on nouveau + * set prime on buffer, + * retrive buffer from intel + * close prime_fd, + * unref buffers + */ +static int test2(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd; + struct nouveau_bo *nvbo; + + ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, + 0, BO_SIZE, NULL, &nvbo); + if (ret < 0) + return ret; + ret = nouveau_bo_set_prime(nvbo, &prime_fd); + if (ret < 0) + return ret; + + test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE); + close(prime_fd); + if (!test_intel_bo) + return -1; + + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return 0; +} + +/* + * allocate intel, give to nouveau, map on nouveau + * write 0xdeadbeef, non-gtt map on intel, read + */ +static int test3(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd; + struct nouveau_bo *nvbo = NULL; + uint32_t *ptr; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096); + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo); + if (ret < 0) { + fprintf(stderr,"failed to ref prime buffer %d\n", ret); + close(prime_fd); + goto free_intel; + } + close(prime_fd); + goto free_intel; + + ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient); + if (ret < 0) { + fprintf(stderr,"failed to map nouveau bo\n"); + goto out; + } + + ptr = nvbo->map; + *ptr = 0xdeadbeef; + + drm_intel_bo_map(test_intel_bo, 1); + + ptr = test_intel_bo->virtual; + + if (*ptr != 0xdeadbeef) { + fprintf(stderr,"mapped value doesn't match\n"); + ret = -1; + } +out: + nouveau_bo_ref(NULL, &nvbo); +free_intel: + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +/* + * allocate intel, give to nouveau, map on nouveau + * write 0xdeadbeef, gtt map on intel, read + */ +static int test4(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd; + struct nouveau_bo *nvbo = NULL; + uint32_t *ptr; + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096); + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo); + close(prime_fd); + if (ret < 0) { + fprintf(stderr,"failed to ref prime buffer\n"); + return ret; + } + + ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient); + if (ret < 0) { + fprintf(stderr,"failed to map nouveau bo\n"); + goto out; + } + + + ptr = nvbo->map; + *ptr = 0xdeadbeef; + + drm_intel_gem_bo_map_gtt(test_intel_bo); + ptr = test_intel_bo->virtual; + + if (*ptr != 0xdeadbeef) { + fprintf(stderr,"mapped value doesn't match\n"); + ret = -1; + } +out: + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +/* test drm_intel_bo_map doesn't work properly, + this tries to map the backing shmem fd, which doesn't exist + for these objects */ +static int test5(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd; + struct nouveau_bo *nvbo; + uint32_t *ptr; + + ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, + 0, BO_SIZE, NULL, &nvbo); + if (ret < 0) + return ret; + ret = nouveau_bo_set_prime(nvbo, &prime_fd); + if (ret < 0) + return ret; + + test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE); + close(prime_fd); + if (!test_intel_bo) + return -1; + + ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient); + if (ret < 0) { + fprintf(stderr,"failed to map nouveau bo\n"); + goto out; + } + + ptr = nvbo->map; + *ptr = 0xdeadbeef; + + ret = drm_intel_bo_map(test_intel_bo, 0); + if (ret != 0) { + /* failed to map the bo is expected */ + ret = 0; + goto out; + } + if (!test_intel_bo->virtual) { + ret = 0; + goto out; + } + ptr = test_intel_bo->virtual; + + if (*ptr != 0xdeadbeef) { + fprintf(stderr,"mapped value doesn't match %08x\n", *ptr); + ret = -1; + } + out: + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +/* test drm_intel_bo_map_gtt works properly, + this tries to map the backing shmem fd, which doesn't exist + for these objects */ +static int test6(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd; + struct nouveau_bo *nvbo; + uint32_t *ptr; + + ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, + 0, BO_SIZE, NULL, &nvbo); + if (ret < 0) + return ret; + ret = nouveau_bo_set_prime(nvbo, &prime_fd); + if (ret < 0) + return ret; + + test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE); + close(prime_fd); + if (!test_intel_bo) + return -1; + + ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient); + if (ret < 0) { + fprintf(stderr,"failed to map nouveau bo\n"); + goto out; + } + + ptr = nvbo->map; + *ptr = 0xdeadbeef; + *(ptr + 1) = 0xa55a55; + + ret = drm_intel_gem_bo_map_gtt(test_intel_bo); + if (ret != 0) { + fprintf(stderr,"failed to map bo\n"); + goto out; + } + if (!test_intel_bo->virtual) { + ret = -1; + fprintf(stderr,"failed to map bo\n"); + goto out; + } + ptr = test_intel_bo->virtual; + + if (*ptr != 0xdeadbeef) { + fprintf(stderr,"mapped value doesn't match %08x %08x\n", *ptr, *(ptr + 1)); + ret = -1; + } + out: + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +static int do_read(int fd, int handle, void *buf, int offset, int size) +{ + struct drm_i915_gem_pread intel_pread; + + /* Ensure that we don't have any convenient data in buf in case + * we fail. + */ + memset(buf, 0xd0, size); + + memset(&intel_pread, 0, sizeof(intel_pread)); + intel_pread.handle = handle; + intel_pread.data_ptr = (uintptr_t)buf; + intel_pread.size = size; + intel_pread.offset = offset; + + return ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &intel_pread); +} + +static int do_write(int fd, int handle, void *buf, int offset, int size) +{ + struct drm_i915_gem_pwrite intel_pwrite; + + memset(&intel_pwrite, 0, sizeof(intel_pwrite)); + intel_pwrite.handle = handle; + intel_pwrite.data_ptr = (uintptr_t)buf; + intel_pwrite.size = size; + intel_pwrite.offset = offset; + + return ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &intel_pwrite); +} + +/* test 7 - import from nouveau into intel, test pread/pwrite fail */ +static int test7(void) +{ + int ret; + drm_intel_bo *test_intel_bo; + int prime_fd; + struct nouveau_bo *nvbo; + uint32_t *ptr; + uint32_t buf[64]; + + ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, + 0, BO_SIZE, NULL, &nvbo); + if (ret < 0) + return ret; + ret = nouveau_bo_set_prime(nvbo, &prime_fd); + if (ret < 0) + return ret; + + test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE); + close(prime_fd); + if (!test_intel_bo) + return -1; + + ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient); + if (ret < 0) { + fprintf(stderr,"failed to map nouveau bo\n"); + goto out; + } + + ptr = nvbo->map; + *ptr = 0xdeadbeef; + + ret = do_read(intel_fd, test_intel_bo->handle, buf, 0, 256); + if (ret != -1) { + fprintf(stderr,"pread succeedded %d\n", ret); + goto out; + } + buf[0] = 0xabcdef55; + + ret = do_write(intel_fd, test_intel_bo->handle, buf, 0, 4); + if (ret != -1) { + fprintf(stderr,"pwrite succeedded\n"); + goto out; + } + ret = 0; + out: + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +static void +set_bo(drm_intel_bo *bo, uint32_t val, int width, int height) +{ + int size = width * height; + uint32_t *vaddr; + + drm_intel_gem_bo_start_gtt_access(bo, true); + vaddr = bo->virtual; + while (size--) + *vaddr++ = val; +} + +static drm_intel_bo * +create_bo(drm_intel_bufmgr *ibufmgr, uint32_t val, int width, int height) +{ + drm_intel_bo *bo; + + bo = drm_intel_bo_alloc(ibufmgr, "bo", 4*width*height, 0); + assert(bo); + + /* gtt map doesn't have a write parameter, so just keep the mapping + * around (to avoid the set_domain with the gtt write domain set) and + * manually tell the kernel when we start access the gtt. */ + drm_intel_gem_bo_map_gtt(bo); + + set_bo(bo, val, width, height); + + return bo; +} + +/* use intel hw to fill the BO with a blit from another BO, + then readback from the nouveau bo, check value is correct */ +static int test8(void) +{ + int ret; + drm_intel_bo *test_intel_bo, *src_bo; + int prime_fd; + struct nouveau_bo *nvbo = NULL; + uint32_t *ptr; + + src_bo = create_bo(bufmgr, 0xaa55aa55, 256, 1); + + test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096); + + drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd); + + ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo); + close(prime_fd); + if (ret < 0) { + fprintf(stderr,"failed to ref prime buffer\n"); + return ret; + } + + intel_copy_bo(intel_batch, test_intel_bo, src_bo, 256, 1); + + ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient); + if (ret < 0) { + fprintf(stderr,"failed to map nouveau bo\n"); + goto out; + } + + drm_intel_bo_map(test_intel_bo, 0); + + ptr = nvbo->map; + if (*ptr != 0xaa55aa55) { + fprintf(stderr,"mapped value doesn't match\n"); + ret = -1; + } +out: + nouveau_bo_ref(NULL, &nvbo); + drm_intel_bo_unreference(test_intel_bo); + return ret; +} + +/* test 8 use nouveau to do blit */ + +/* test 9 nouveau copy engine?? */ + +int main(int argc, char **argv) +{ + int ret; + + ret = find_and_open_devices(); + if (ret < 0) + return ret; + + if (nouveau_fd == -1 || intel_fd == -1) { + fprintf(stderr,"failed to find intel and nouveau GPU\n"); + return 77; + } + + /* set up intel bufmgr */ + bufmgr = drm_intel_bufmgr_gem_init(intel_fd, 4096); + if (!bufmgr) + return -1; + /* Do not enable reuse, we share (almost) all buffers. */ + //drm_intel_bufmgr_gem_enable_reuse(bufmgr); + + /* set up nouveau bufmgr */ + ret = nouveau_device_wrap(nouveau_fd, 0, &ndev); + if (ret < 0) { + fprintf(stderr,"failed to wrap nouveau device\n"); + return 77; + } + + ret = nouveau_client_new(ndev, &nclient); + if (ret < 0) { + fprintf(stderr,"failed to setup nouveau client\n"); + return -1; + } + + /* set up an intel batch buffer */ + devid = intel_get_drm_devid(intel_fd); + intel_batch = intel_batchbuffer_alloc(bufmgr, devid); + + /* create an object on the i915 */ + ret = test1(); + if (ret) + fprintf(stderr,"prime_test: failed test 1\n"); + + ret = test2(); + if (ret) + fprintf(stderr,"prime_test: failed test 2\n"); + + ret = test3(); + if (ret) + fprintf(stderr,"prime_test: failed test 3\n"); + + ret = test4(); + if (ret) + fprintf(stderr,"prime_test: failed test 4\n"); + + ret = test5(); + if (ret) + fprintf(stderr,"prime_test: failed test 5\n"); + + ret = test6(); + if (ret) + fprintf(stderr,"prime_test: failed test 6\n"); + + ret = test7(); + if (ret) + fprintf(stderr,"prime_test: failed test 7\n"); + + ret = test8(); + if (ret) + fprintf(stderr,"prime_test: failed test 8\n"); + + intel_batchbuffer_free(intel_batch); + + nouveau_device_del(&ndev); + drm_intel_bufmgr_destroy(bufmgr); + + close(intel_fd); + close(nouveau_fd); + + return ret; +} diff --git a/tests/prime_self_import.c b/tests/prime_self_import.c new file mode 100644 index 00000000..111ed4da --- /dev/null +++ b/tests/prime_self_import.c @@ -0,0 +1,123 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +/* + * Testcase: Check whether prime import/export works on the same device + * + * ... but with different fds, i.e. the wayland usecase. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" + +#define BO_SIZE (16*1024) + +static void +check_bo(int fd1, uint32_t handle1, int fd2, uint32_t handle2) +{ + char *ptr1, *ptr2; + static char counter = 0; + int i; + + ptr1 = gem_mmap(fd1, handle1, BO_SIZE, PROT_READ | PROT_WRITE); + ptr2 = gem_mmap(fd2, handle2, BO_SIZE, PROT_READ | PROT_WRITE); + + assert(ptr1); + + /* check whether it's still our old object first. */ + for (i = 0; i < BO_SIZE; i++) { + assert(ptr1[i] == counter); + assert(ptr2[i] == counter); + } + + counter++; + + memset(ptr1, counter, BO_SIZE); + assert(memcmp(ptr1, ptr2, BO_SIZE) == 0); + + munmap(ptr1, BO_SIZE); + munmap(ptr2, BO_SIZE); +} + +int main(int argc, char **argv) +{ + int fd1, fd2; + uint32_t handle, handle_import1, handle_import2, handle_selfimport; + int dma_buf_fd; + + fd1 = drm_open_any(); + fd2 = drm_open_any(); + + handle = gem_create(fd1, BO_SIZE); + + dma_buf_fd = prime_handle_to_fd(fd1, handle); + handle_import1 = prime_fd_to_handle(fd2, dma_buf_fd); + + check_bo(fd1, handle, fd2, handle_import1); + + /* reimport should give us the same handle so that userspace can check + * whether it has that bo already somewhere. */ + handle_import2 = prime_fd_to_handle(fd2, dma_buf_fd); + assert(handle_import1 == handle_import2); + + /* Same for re-importing on the exporting fd. */ + handle_selfimport = prime_fd_to_handle(fd1, dma_buf_fd); + assert(handle == handle_selfimport); + + /* close dma_buf, check whether nothing disappears. */ + close(dma_buf_fd); + check_bo(fd1, handle, fd2, handle_import1); + + gem_close(fd1, handle); + check_bo(fd2, handle_import1, fd2, handle_import1); + + /* re-import into old exporter */ + dma_buf_fd = prime_handle_to_fd(fd2, handle_import1); + /* but drop all references to the obj in between */ + gem_close(fd2, handle_import1); + handle = prime_fd_to_handle(fd1, dma_buf_fd); + handle_import1 = prime_fd_to_handle(fd2, dma_buf_fd); + check_bo(fd1, handle, fd2, handle_import1); + + /* Completely rip out exporting fd. */ + close(fd1); + check_bo(fd2, handle_import1, fd2, handle_import1); + + return 0; +} diff --git a/tests/sysfs_edid_timing b/tests/sysfs_edid_timing new file mode 100755 index 00000000..3a8c6c0e --- /dev/null +++ b/tests/sysfs_edid_timing @@ -0,0 +1,20 @@ +#!/bin/sh +# +# This check the time we take to read the content of all the possible connectors. +# Without the edid -ENXIO patch (http://permalink.gmane.org/gmane.comp.video.dri.devel/62083), +# we sometimes take a *really* long time. So let's just check for some reasonable timing here +# + +TIME1=$(date +%s%N) +cat $(find /sys/devices/|grep drm | grep /status) > /dev/null +TIME2=$(date +%s%N) + +# time in ms +RES=$(((TIME2 - TIME1) / 1000000)) + +if [ $RES -gt 600 ]; then + echo "Talking to outputs took ${RES}ms, something is wrong" + exit 1 +fi + +exit 0 diff --git a/tests/sysfs_l3_parity b/tests/sysfs_l3_parity new file mode 100755 index 00000000..6f814a13 --- /dev/null +++ b/tests/sysfs_l3_parity @@ -0,0 +1,27 @@ +#!/bin/bash + +if ! find /sys/class/drm/card*/ | grep l3_parity > /dev/null ; then + echo "no l3_parity interface, skipping test" + exit 77 +fi + +SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )" +. $SOURCE_DIR/drm_lib.sh + +$SOURCE_DIR/../tools/intel_l3_parity -c + +#Check that we can remap a row +$SOURCE_DIR/../tools/intel_l3_parity 0,0,0 +disabled=`$SOURCE_DIR/../tools/intel_l3_parity | grep -c 'Row 0, Bank 0, Subbank 0 is disabled'` +if [ "$disabled" != "1" ] ; then + echo "Fail" + exit 1 +fi + +$SOURCE_DIR/../tools/intel_l3_parity -c + +#Check that we can clear remaps +if [ `$SOURCE_DIR/../tools/intel_l3_parity | wc -c` != "0" ] ; then + echo "Fail" + exit 1 +fi diff --git a/tests/sysfs_rc6_residency.c b/tests/sysfs_rc6_residency.c new file mode 100644 index 00000000..2f33697a --- /dev/null +++ b/tests/sysfs_rc6_residency.c @@ -0,0 +1,119 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "drmtest.h" + +#define SLEEP_DURATION 3000 // in milliseconds +#define RC6_FUDGE 900 // in milliseconds + +static unsigned int readit(const char *path) +{ + unsigned int ret; + + FILE *file; + file = fopen(path, "r"); + if (file == NULL) { + fprintf(stderr, "Couldn't open %s (%d)\n", path, errno); + abort(); + } + fscanf(file, "%u", &ret); + fclose(file); + + return ret; +} + +int main(int argc, char *argv[]) +{ + const int device = drm_get_card(0); + char *path, *pathp, *pathpp; + int fd, ret; + unsigned int value1, value1p, value1pp, value2, value2p, value2pp; + FILE *file; + int diff; + + /* Use drm_open_any to verify device existence */ + fd = drm_open_any(); + close(fd); + + ret = asprintf(&path, "/sys/class/drm/card%d/power/rc6_enable", device); + assert(ret != -1); + + /* For some reason my ivb isn't idle even after syncing up with the gpu. + * Let's add a sleept just to make it happy. */ + sleep(5); + + file = fopen(path, "r"); + if (!file) { + printf("kernel too old or rc6 not supported on this platform.\n"); + exit(77); + } + + /* claim success if no rc6 enabled. */ + if (readit(path) == 0) + exit(EXIT_SUCCESS); + + ret = asprintf(&path, "/sys/class/drm/card%d/power/rc6_residency_ms", device); + assert(ret != -1); + ret = asprintf(&pathp, "/sys/class/drm/card%d/power/rc6p_residency_ms", device); + assert(ret != -1); + ret = asprintf(&pathpp, "/sys/class/drm/card%d/power/rc6pp_residency_ms", device); + assert(ret != -1); + + value1 = readit(path); + value1p = readit(pathp); + value1pp = readit(pathpp); + sleep(SLEEP_DURATION / 1000); + value2 = readit(path); + value2p = readit(pathp); + value2pp = readit(pathpp); + + free(pathpp); + free(pathp); + free(path); + + diff = (value2pp - value1pp) + + (value2p - value1p) + + (value2 - value1); + + if (diff > (SLEEP_DURATION + RC6_FUDGE)) { + fprintf(stderr, "Diff was too high. That is unpossible\n"); + exit(EXIT_FAILURE); + } + if (diff < (SLEEP_DURATION - RC6_FUDGE)) { + fprintf(stderr, "GPU was not in RC6 long enough. Check that " + "the GPU is as idle as possible (ie. no X, " + "running and running no other tests)\n"); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +} diff --git a/tests/testdisplay.c b/tests/testdisplay.c new file mode 100644 index 00000000..14d7da39 --- /dev/null +++ b/tests/testdisplay.c @@ -0,0 +1,765 @@ +/* + * Copyright 2010 Intel Corporation + * Jesse Barnes <jesse.barnes@intel.com> + * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS 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. + */ + +/* + * This program is intended for testing of display functionality. It should + * allow for testing of + * - hotplug + * - mode setting + * - clone & twin modes + * - panel fitting + * - test patterns & pixel generators + * Additional programs can test the detected outputs against VBT provided + * device lists (both docked & undocked). + * + * TODO: + * - pixel generator in transcoder + * - test pattern reg in pipe + * - test patterns on outputs (e.g. TV) + * - handle hotplug (leaks crtcs, can't handle clones) + * - allow mode force + * - expose output specific controls + * - e.g. DDC-CI brightness + * - HDMI controls + * - panel brightness + * - DP commands (e.g. poweroff) + * - verify outputs against VBT/physical connectors + */ +#include "config.h" + +#include <assert.h> +#include <cairo.h> +#include <errno.h> +#include <math.h> +#include <stdint.h> +#include <unistd.h> +#include <sys/poll.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/ioctl.h> + +#include "i915_drm.h" +#include "drmtest.h" +#include "testdisplay.h" + +#include <stdlib.h> +#include <signal.h> + +drmModeRes *resources; +int drm_fd, modes; +int dump_info = 0, test_all_modes =0, test_preferred_mode = 0, force_mode = 0, + test_plane, enable_tiling; +int sleep_between_modes = 5; +uint32_t depth = 24, stride, bpp; +int qr_code = 0; + +drmModeModeInfo force_timing; + +int crtc_x, crtc_y, crtc_w, crtc_h, width, height; +unsigned int plane_fb_id; +unsigned int plane_crtc_id; +unsigned int plane_id; +int plane_width, plane_height; +static const uint32_t SPRITE_COLOR_KEY = 0x00aaaaaa; +uint32_t *fb_ptr; + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct type_name { + int type; + const char *name; +}; + +#define type_name_fn(res) \ +static const char * res##_str(int type) { \ + unsigned int i; \ + for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ + if (res##_names[i].type == type) \ + return res##_names[i].name; \ + } \ + return "(invalid)"; \ +} + +struct type_name encoder_type_names[] = { + { DRM_MODE_ENCODER_NONE, "none" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, +}; + +type_name_fn(encoder_type) + +struct type_name connector_status_names[] = { + { DRM_MODE_CONNECTED, "connected" }, + { DRM_MODE_DISCONNECTED, "disconnected" }, + { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, +}; + +type_name_fn(connector_status) + +struct type_name connector_type_names[] = { + { DRM_MODE_CONNECTOR_Unknown, "unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, + { DRM_MODE_CONNECTOR_TV, "TV" }, + { DRM_MODE_CONNECTOR_eDP, "Embedded DisplayPort" }, +}; + +type_name_fn(connector_type) + +/* + * Mode setting with the kernel interfaces is a bit of a chore. + * First you have to find the connector in question and make sure the + * requested mode is available. + * Then you need to find the encoder attached to that connector so you + * can bind it with a free crtc. + */ +struct connector { + uint32_t id; + int mode_valid; + drmModeModeInfo mode; + drmModeEncoder *encoder; + drmModeConnector *connector; + int crtc; + int pipe; +}; + +static void dump_connectors_fd(int drmfd) +{ + int i, j; + + drmModeRes *mode_resources = drmModeGetResources(drmfd); + + if (!mode_resources) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + return; + } + + printf("Connectors:\n"); + printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n"); + for (i = 0; i < mode_resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(drmfd, mode_resources->connectors[i]); + if (!connector) { + fprintf(stderr, "could not get connector %i: %s\n", + mode_resources->connectors[i], strerror(errno)); + continue; + } + + printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n", + connector->connector_id, + connector->encoder_id, + connector_status_str(connector->connection), + connector_type_str(connector->connector_type), + connector->mmWidth, connector->mmHeight, + connector->count_modes); + + if (!connector->count_modes) + continue; + + printf(" modes:\n"); + printf(" name refresh (Hz) hdisp hss hse htot vdisp " + "vss vse vtot flags type clock\n"); + for (j = 0; j < connector->count_modes; j++) + kmstest_dump_mode(&connector->modes[j]); + + drmModeFreeConnector(connector); + } + printf("\n"); + + drmModeFreeResources(mode_resources); +} + +static void dump_crtcs_fd(int drmfd) +{ + int i; + drmModeRes *mode_resources = drmModeGetResources(drmfd); + + printf("CRTCs:\n"); + printf("id\tfb\tpos\tsize\n"); + for (i = 0; i < mode_resources->count_crtcs; i++) { + drmModeCrtc *crtc; + + crtc = drmModeGetCrtc(drmfd, mode_resources->crtcs[i]); + if (!crtc) { + fprintf(stderr, "could not get crtc %i: %s\n", + mode_resources->crtcs[i], strerror(errno)); + continue; + } + printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", + crtc->crtc_id, + crtc->buffer_id, + crtc->x, crtc->y, + crtc->width, crtc->height); + kmstest_dump_mode(&crtc->mode); + + drmModeFreeCrtc(crtc); + } + printf("\n"); + + drmModeFreeResources(mode_resources); +} + +static void connector_find_preferred_mode(struct connector *c) +{ + drmModeConnector *connector; + drmModeEncoder *encoder = NULL; + int i, j; + + /* First, find the connector & mode */ + c->mode_valid = 0; + connector = drmModeGetConnector(drm_fd, c->id); + if (!connector) { + fprintf(stderr, "could not get connector %d: %s\n", + c->id, strerror(errno)); + drmModeFreeConnector(connector); + return; + } + + if (connector->connection != DRM_MODE_CONNECTED) { + drmModeFreeConnector(connector); + return; + } + + if (!connector->count_modes) { + fprintf(stderr, "connector %d has no modes\n", c->id); + drmModeFreeConnector(connector); + return; + } + + if (connector->connector_id != c->id) { + fprintf(stderr, "connector id doesn't match (%d != %d)\n", + connector->connector_id, c->id); + drmModeFreeConnector(connector); + return; + } + + for (j = 0; j < connector->count_modes; j++) { + c->mode = connector->modes[j]; + if (c->mode.type & DRM_MODE_TYPE_PREFERRED) { + c->mode_valid = 1; + break; + } + } + + if (!c->mode_valid) { + if (connector->count_modes > 0) { + /* use the first mode as test mode */ + c->mode = connector->modes[0]; + c->mode_valid = 1; + } + else { + fprintf(stderr, "failed to find any modes on connector %d\n", + c->id); + return; + } + } + + /* Now get the encoder */ + for (i = 0; i < connector->count_encoders; i++) { + encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]); + + if (!encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + drmModeFreeEncoder(encoder); + continue; + } + + break; + } + + c->encoder = encoder; + + if (i == resources->count_encoders) { + fprintf(stderr, "failed to find encoder\n"); + c->mode_valid = 0; + return; + } + + /* Find first CRTC not in use */ + for (i = 0; i < resources->count_crtcs; i++) { + if (resources->crtcs[i] && (c->encoder->possible_crtcs & (1<<i))) + break; + } + c->crtc = resources->crtcs[i]; + c->pipe = i; + + if(test_preferred_mode || force_mode) + resources->crtcs[i] = 0; + + c->connector = connector; +} + +static void +paint_color_key(void) +{ + int i, j; + + for (i = crtc_y; i < crtc_y + crtc_h; i++) + for (j = crtc_x; j < crtc_x + crtc_w; j++) { + uint32_t offset; + + offset = (i * width) + j; + fb_ptr[offset] = SPRITE_COLOR_KEY; + } +} + +static void paint_image(cairo_t *cr, const char *file) +{ + int img_x, img_y, img_w, img_h, img_w_o, img_h_o; + double img_w_scale, img_h_scale; + + cairo_surface_t *image; + + img_y = height * (0.10 ); + img_h = height * 0.08 * 4; + img_w = img_h; + + img_x = (width / 2) - (img_w / 2); + + image = cairo_image_surface_create_from_png(file); + + img_w_o = cairo_image_surface_get_width(image); + img_h_o = cairo_image_surface_get_height(image); + + cairo_translate(cr, img_x, img_y); + + img_w_scale = (double)img_w / (double)img_w_o; + img_h_scale = (double)img_h / (double)img_h_o; + cairo_scale(cr, img_w_scale, img_h_scale); + + cairo_set_source_surface(cr, image, 0, 0); + cairo_scale(cr, 1, 1); + + cairo_paint(cr); + cairo_surface_destroy(image); +} + +static void +paint_output_info(cairo_t *cr, int l_width, int l_height, void *priv) +{ + struct connector *c = priv; + cairo_text_extents_t name_extents, mode_extents; + char name_buf[128], mode_buf[128]; + int i, x, y, modes_x, modes_y; + + /* Get text extents for each string */ + snprintf(name_buf, sizeof name_buf, "%s", + connector_type_str(c->connector->connector_type)); + cairo_set_font_size(cr, 48); + cairo_select_font_face(cr, "Helvetica", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_text_extents(cr, name_buf, &name_extents); + + snprintf(mode_buf, sizeof mode_buf, "%s @ %dHz on %s encoder", + c->mode.name, c->mode.vrefresh, + encoder_type_str(c->encoder->encoder_type)); + cairo_set_font_size(cr, 36); + cairo_text_extents(cr, mode_buf, &mode_extents); + + /* Paint output name */ + x = l_width / 2; + x -= name_extents.width / 2; + y = l_height / 2; + y -= (name_extents.height / 2) - (mode_extents.height / 2) - 10; + cairo_set_font_size(cr, 48); + cairo_move_to(cr, x, y); + cairo_text_path(cr, name_buf); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_fill(cr); + + /* Paint mode name */ + x = l_width / 2; + x -= mode_extents.width / 2; + modes_x = x; + y = l_height / 2; + y += (mode_extents.height / 2) + (name_extents.height / 2) + 10; + cairo_set_font_size(cr, 36); + cairo_move_to(cr, x, y); + cairo_text_path(cr, mode_buf); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_fill(cr); + + /* List available modes */ + snprintf(mode_buf, sizeof mode_buf, "Available modes:"); + cairo_set_font_size(cr, 18); + cairo_text_extents(cr, mode_buf, &mode_extents); + x = modes_x; + modes_x = x + mode_extents.width; + y += mode_extents.height + 10; + modes_y = y; + cairo_move_to(cr, x, y); + cairo_text_path(cr, mode_buf); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_fill(cr); + + for (i = 0; i < c->connector->count_modes; i++) { + snprintf(mode_buf, sizeof mode_buf, "%s @ %dHz", + c->connector->modes[i].name, + c->connector->modes[i].vrefresh); + cairo_set_font_size(cr, 18); + cairo_text_extents(cr, mode_buf, &mode_extents); + x = modes_x - mode_extents.width; /* right justify modes */ + y += mode_extents.height + 10; + if (y + mode_extents.height >= height) { + y = modes_y + mode_extents.height + 10; + modes_x += mode_extents.width + 10; + x = modes_x - mode_extents.width; + } + cairo_move_to(cr, x, y); + cairo_text_path(cr, mode_buf); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_fill(cr); + } + + if (qr_code) + paint_image(cr, "./pass.png"); +} + +static void sighandler(int signo) +{ + return; +} + +static void set_single(void) +{ + int sigs[] = { SIGUSR1 }; + struct sigaction sa; + sa.sa_handler = sighandler; + + sigemptyset(&sa.sa_mask); + + if (sigaction(sigs[0], &sa, NULL) == -1) + perror("Could not set signal handler"); +} + +static void +set_mode(struct connector *c) +{ + unsigned int fb_id = 0; + int j, test_mode_num; + + if (depth <= 8) + bpp = 8; + else if (depth > 8 && depth <= 16) + bpp = 16; + else if (depth > 16 && depth <= 32) + bpp = 32; + + connector_find_preferred_mode(c); + if (!c->mode_valid) + return; + + test_mode_num = 1; + if (force_mode){ + memcpy( &c->mode, &force_timing, sizeof(force_timing)); + c->mode.vrefresh =(force_timing.clock*1e3)/(force_timing.htotal*force_timing.vtotal); + c->mode_valid = 1; + sprintf(c->mode.name, "%dx%d", force_timing.hdisplay, force_timing.vdisplay); + } else if (test_all_modes) + test_mode_num = c->connector->count_modes; + + for (j = 0; j < test_mode_num; j++) { + struct kmstest_fb fb_info; + + if (test_all_modes) + c->mode = c->connector->modes[j]; + + if (!c->mode_valid) + continue; + + width = c->mode.hdisplay; + height = c->mode.vdisplay; + + fb_id = kmstest_create_fb(drm_fd, width, height, bpp, depth, + enable_tiling, &fb_info, + paint_output_info, c); + + fb_ptr = gem_mmap(drm_fd, fb_info.gem_handle, + fb_info.size, PROT_READ | PROT_WRITE); + assert(fb_ptr); + paint_color_key(); + + gem_close(drm_fd, fb_info.gem_handle); + + fprintf(stdout, "CRTS(%u):",c->crtc); + kmstest_dump_mode(&c->mode); + if (drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0, + &c->id, 1, &c->mode)) { + fprintf(stderr, "failed to set mode (%dx%d@%dHz): %s\n", + width, height, c->mode.vrefresh, + strerror(errno)); + continue; + } + + if (sleep_between_modes && test_all_modes && !qr_code) + sleep(sleep_between_modes); + + if (qr_code){ + set_single(); + pause(); + } + + } + + if(test_all_modes){ + drmModeRmFB(drm_fd,fb_id); + drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0, &c->id, 1, 0); + } + + drmModeFreeEncoder(c->encoder); + drmModeFreeConnector(c->connector); +} + +/* + * Re-probe outputs and light up as many as possible. + * + * On Intel, we have two CRTCs that we can drive independently with + * different timings and scanout buffers. + * + * Each connector has a corresponding encoder, except in the SDVO case + * where an encoder may have multiple connectors. + */ +int update_display(void) +{ + struct connector *connectors; + int c; + + resources = drmModeGetResources(drm_fd); + if (!resources) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + return 0; + } + + connectors = calloc(resources->count_connectors, + sizeof(struct connector)); + if (!connectors) + return 0; + + if (dump_info) { + dump_connectors_fd(drm_fd); + dump_crtcs_fd(drm_fd); + } + + if (test_preferred_mode || test_all_modes || force_mode) { + /* Find any connected displays */ + for (c = 0; c < resources->count_connectors; c++) { + connectors[c].id = resources->connectors[c]; + set_mode(&connectors[c]); + } + } + drmModeFreeResources(resources); + return 1; +} + +static char optstr[] = "hiaf:s:d:p:mrt"; + +static void usage(char *name) +{ + fprintf(stderr, "usage: %s [-hiasdpmtf]\n", name); + fprintf(stderr, "\t-i\tdump info\n"); + fprintf(stderr, "\t-a\ttest all modes\n"); + fprintf(stderr, "\t-s\t<duration>\tsleep between each mode test\n"); + fprintf(stderr, "\t-d\t<depth>\tbit depth of scanout buffer\n"); + fprintf(stderr, "\t-p\t<planew,h>,<crtcx,y>,<crtcw,h> test overlay plane\n"); + fprintf(stderr, "\t-m\ttest the preferred mode\n"); + fprintf(stderr, "\t-t\tuse a tiled framebuffer\n"); + fprintf(stderr, "\t-r\tprint a QR code on the screen whose content is \"pass\" for the automatic test\n"); + fprintf(stderr, "\t-f\t<clock MHz>,<hdisp>,<hsync-start>,<hsync-end>,<htotal>,\n"); + fprintf(stderr, "\t\t<vdisp>,<vsync-start>,<vsync-end>,<vtotal>\n"); + fprintf(stderr, "\t\ttest force mode\n"); + fprintf(stderr, "\tDefault is to test all modes.\n"); + exit(0); +} + +#define dump_resource(res) if (res) dump_##res() + +static gboolean input_event(GIOChannel *source, GIOCondition condition, + gpointer data) +{ + gchar buf[2]; + gsize count; + + count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf)); + if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) { + exit(0); + } + + return TRUE; +} + +static void enter_exec_path( char **argv ) +{ + char *exec_path = NULL; + char *pos = NULL; + short len_path = 0; + + len_path = strlen( argv[0] ); + exec_path = (char*) malloc(len_path); + + memcpy(exec_path, argv[0], len_path); + pos = strrchr(exec_path, '/'); + if (pos != NULL) + *(pos+1) = '\0'; + + chdir(exec_path); + free(exec_path); +} + +int main(int argc, char **argv) +{ + int c; + int ret = 0; + GIOChannel *stdinchannel; + GMainLoop *mainloop; + float force_clock; + + enter_exec_path( argv ); + + opterr = 0; + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 'i': + dump_info = 1; + break; + case 'a': + test_all_modes = 1; + break; + case 'f': + force_mode = 1; + if(sscanf(optarg,"%f,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu", + &force_clock,&force_timing.hdisplay, &force_timing.hsync_start,&force_timing.hsync_end,&force_timing.htotal, + &force_timing.vdisplay, &force_timing.vsync_start, &force_timing.vsync_end, &force_timing.vtotal)!= 9) + usage(argv[0]); + force_timing.clock = force_clock*1000; + + break; + case 's': + sleep_between_modes = atoi(optarg); + break; + case 'd': + depth = atoi(optarg); + fprintf(stderr, "using depth %d\n", depth); + break; + case 'p': + if (sscanf(optarg, "%d,%d,%d,%d,%d,%d", &plane_width, + &plane_height, &crtc_x, &crtc_y, + &crtc_w, &crtc_h) != 6) + usage(argv[0]); + test_plane = 1; + break; + case 'm': + test_preferred_mode = 1; + break; + case 't': + enable_tiling = 1; + break; + case 'r': + qr_code = 1; + break; + default: + fprintf(stderr, "unknown option %c\n", c); + /* fall through */ + case 'h': + usage(argv[0]); + break; + } + } + if (!test_all_modes && !force_mode && !dump_info && + !test_preferred_mode) + test_all_modes = 1; + + drm_fd = drm_open_any(); + + mainloop = g_main_loop_new(NULL, FALSE); + if (!mainloop) { + fprintf(stderr, "failed to create glib mainloop\n"); + ret = -1; + goto out_close; + } + + if (!testdisplay_setup_hotplug()) { + fprintf(stderr, "failed to initialize hotplug support\n"); + goto out_mainloop; + } + + stdinchannel = g_io_channel_unix_new(0); + if (!stdinchannel) { + fprintf(stderr, "failed to create stdin GIO channel\n"); + goto out_hotplug; + } + + ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event, + NULL); + if (ret < 0) { + fprintf(stderr, "failed to add watch on stdin GIO channel\n"); + goto out_stdio; + } + + ret = 0; + + if (!update_display()) { + ret = 1; + goto out_stdio; + } + + if (dump_info || test_all_modes) + goto out_stdio; + + g_main_loop_run(mainloop); + +out_stdio: + g_io_channel_shutdown(stdinchannel, TRUE, NULL); +out_hotplug: + testdisplay_cleanup_hotplug(); +out_mainloop: + g_main_loop_unref(mainloop); +out_close: + close(drm_fd); + + return ret; +} diff --git a/tests/testdisplay.h b/tests/testdisplay.h new file mode 100644 index 00000000..962e6219 --- /dev/null +++ b/tests/testdisplay.h @@ -0,0 +1,35 @@ +/* + * Copyright 2010 Intel Corporation + * Jesse Barnes <jesse.barnes@intel.com> + * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <glib.h> + +extern int drm_fd; + +gboolean testdisplay_setup_hotplug(void); +void testdisplay_cleanup_hotplug(void); + +/* called by the hotplug code */ +int update_display(void); diff --git a/tests/testdisplay_hotplug.c b/tests/testdisplay_hotplug.c new file mode 100644 index 00000000..3f80dc73 --- /dev/null +++ b/tests/testdisplay_hotplug.c @@ -0,0 +1,136 @@ +/* + * Copyright 2010 Intel Corporation + * Jesse Barnes <jesse.barnes@intel.com> + * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS 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 <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "testdisplay.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_UDEV +#include <libudev.h> +static struct udev_monitor *uevent_monitor; +static struct udev *udev; +static GIOChannel *udevchannel; + +static gboolean hotplug_event(GIOChannel *source, GIOCondition condition, + gpointer data) +{ + struct udev_device *dev; + dev_t udev_devnum; + struct stat s; + const char *hotplug; + + dev = udev_monitor_receive_device(uevent_monitor); + if (!dev) + goto out; + + udev_devnum = udev_device_get_devnum(dev); + fstat(drm_fd, &s); + + hotplug = udev_device_get_property_value(dev, "HOTPLUG"); + + if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 && + hotplug && atoi(hotplug) == 1) + update_display(); + + udev_device_unref(dev); +out: + return TRUE; +} + + +gboolean testdisplay_setup_hotplug(void) +{ + int ret; + + udev = udev_new(); + if (!udev) { + fprintf(stderr, "failed to create udev object\n"); + goto out; + } + + uevent_monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (!uevent_monitor) { + fprintf(stderr, "failed to create udev event monitor\n"); + goto out; + } + + ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor, + "drm", + "drm_minor"); + if (ret < 0) { + fprintf(stderr, "failed to filter for drm events\n"); + goto out; + } + + ret = udev_monitor_enable_receiving(uevent_monitor); + if (ret < 0) { + fprintf(stderr, "failed to enable udev event reception\n"); + goto out; + } + + udevchannel = + g_io_channel_unix_new(udev_monitor_get_fd(uevent_monitor)); + if (!udevchannel) { + fprintf(stderr, "failed to create udev GIO channel\n"); + goto out; + } + + ret = g_io_add_watch(udevchannel, G_IO_IN | G_IO_ERR, hotplug_event, + udev); + if (ret < 0) { + fprintf(stderr, "failed to add watch on udev GIO channel\n"); + goto out; + } + + return TRUE; + +out: + testdisplay_cleanup_hotplug(); + return FALSE; +} + +void testdisplay_cleanup_hotplug(void) +{ + if (udevchannel) + g_io_channel_shutdown(udevchannel, TRUE, NULL); + if (uevent_monitor) + udev_monitor_unref(uevent_monitor); + if (udev) + udev_unref(udev); +} +#else +gboolean testdisplay_setup_hotplug(void) +{ + fprintf(stderr, "no hotplug support on this platform\n"); + return TRUE; +} + +void testdisplay_cleanup_hotplug(void) +{ +} +#endif diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 00000000..c15e3c36 --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,24 @@ +forcewaked +intel_audio_dump +intel_backlight +intel_bios_dumper +intel_bios_reader +intel_disable_clock_gating +intel_dump_decode +intel_error_decode +intel_forcewaked +intel_gpu_dump +intel_gpu_time +intel_gpu_top +intel_gtt +intel_infoframes +intel_l3_parity +intel_lid +intel_panel_fitter +intel_reg_checker +intel_reg_dumper +intel_reg_read +intel_reg_snapshot +intel_reg_write +intel_stepping +# Please keep sorted alphabetically diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 00000000..71fb087f --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,42 @@ +bin_PROGRAMS = \ + intel_disable_clock_gating \ + intel_audio_dump \ + intel_backlight \ + intel_bios_dumper \ + intel_bios_reader \ + intel_error_decode \ + intel_gpu_top \ + intel_gpu_time \ + intel_gtt \ + intel_stepping \ + intel_reg_checker \ + intel_reg_dumper \ + intel_reg_snapshot \ + intel_reg_write \ + intel_reg_read \ + intel_forcewaked \ + intel_dpio_read \ + intel_dpio_write \ + intel_l3_parity + +noinst_PROGRAMS = \ + intel_dump_decode \ + intel_infoframes \ + intel_lid \ + intel_panel_fitter + +dist_bin_SCRIPTS = intel_gpu_abrt + +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib +AM_CFLAGS = $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) +LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) + +intel_dump_decode_SOURCES = \ + intel_dump_decode.c + +intel_error_decode_SOURCES = \ + intel_error_decode.c + +intel_bios_reader_SOURCES = \ + intel_bios_reader.c \ + intel_bios.h diff --git a/tools/intel_audio_dump.c b/tools/intel_audio_dump.c new file mode 100644 index 00000000..8b9da303 --- /dev/null +++ b/tools/intel_audio_dump.c @@ -0,0 +1,1969 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Zhenyu Wang <zhenyu.z.wang@intel.com> + * Wu Fengguang <fengguang.wu@intel.com> + * + */ + +#define _GNU_SOURCE +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <arpa/inet.h> +#include "intel_gpu_tools.h" + +static uint32_t devid; + + +#define BITSTO(n) (n >= sizeof(long) * 8 ? ~0 : (1UL << (n)) - 1) +#define BITMASK(high, low) (BITSTO(high+1) & ~BITSTO(low)) +#define BITS(reg, high, low) (((reg) & (BITMASK(high, low))) >> (low)) +#define BIT(reg, n) BITS(reg, n, n) + +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1: __min2; }) + +#define OPNAME(names, index) \ + names[min_t(unsigned int, index, ARRAY_SIZE(names) - 1)] + +#define dump_reg(reg, desc) \ + do { \ + dword = INREG(reg); \ + printf("%-21s 0x%08x %s\n", # reg, dword, desc); \ + } while (0) + + +static const char *pixel_clock[] = { + [0] = "25.2 / 1.001 MHz", + [1] = "25.2 MHz", + [2] = "27 MHz", + [3] = "27 * 1.001 MHz", + [4] = "54 MHz", + [5] = "54 * 1.001 MHz", + [6] = "74.25 / 1.001 MHz", + [7] = "74.25 MHz", + [8] = "148.5 / 1.001 MHz", + [9] = "148.5 MHz", + [10] = "Reserved", +}; + +static const char *power_state[] = { + [0] = "D0", + [1] = "D1", + [2] = "D2", + [3] = "D3", +}; + +static const char *stream_type[] = { + [0] = "default samples", + [1] = "one bit stream", + [2] = "DST stream", + [3] = "MLP stream", + [4] = "Reserved", +}; + +static const char *dip_port[] = { + [0] = "Reserved", + [1] = "Digital Port B", + [2] = "Digital Port C", + [3] = "Digital Port D", +}; + +static const char *dip_type[] = { + [0] = "Audio DIP Disabled", + [1] = "Audio DIP Enabled", +}; + +static const char *dip_index[] = { + [0] = "Audio DIP", + [1] = "ACP DIP", + [2] = "ISRC1 DIP", + [3] = "ISRC2 DIP", + [4] = "Reserved", +}; + +static const char *dip_trans[] = { + [0] = "disabled", + [1] = "reserved", + [2] = "send once", + [3] = "best effort", +}; + +static const char *video_dip_index[] = { + [0] = "AVI DIP", + [1] = "Vendor-specific DIP", + [2] = "Gamut Metadata DIP", + [3] = "Source Product Description DIP", +}; + +static const char *video_dip_trans[] = { + [0] = "send once", + [1] = "send every vsync", + [2] = "send at least every other vsync", + [3] = "reserved", +}; + +static const char *trans_to_port_sel[] = { + [0] = "no port", + [1] = "Digital Port B", + [2] = "Digital Port C", + [3] = "Digital Port D", + [4] = "reserved", + [5] = "reserved", + [6] = "reserved", + [7] = "reserved", +}; + +static const char *ddi_mode[] = { + [0] = "HDMI mode", + [1] = "DVI mode", + [2] = "DP SST mode", + [3] = "DP MST mode", + [4] = "DP FDI mode", + [5] = "reserved", + [6] = "reserved", + [7] = "reserved", +}; + +static const char *transcoder_select[] = { + [0] = "Transcoder A", + [1] = "Transcoder B", + [2] = "Transcoder C", + [3] = "reserved", +}; + +static const char *dp_port_width[] = { + [0] = "x1 mode", + [1] = "x2 mode", + [2] = "reserved", + [3] = "x4 mode", + [4] = "reserved", + [5] = "reserved", + [6] = "reserved", + [7] = "reserved", +}; + +static const char *bits_per_sample[] = { + [0] = "reserved", + [1] = "16 bits", + [2] = "24 bits", + [3] = "32 bits", + [4] = "20 bits", + [5] = "reserved", +}; + +static const char *sdvo_hdmi_encoding[] = { + [0] = "SDVO", + [1] = "reserved", + [2] = "TMDS", + [3] = "reserved", +}; + +static const char *n_index_value[] = { + [0] = "HDMI", + [1] = "DisplayPort", +}; + +static void do_self_tests(void) +{ + if (BIT(1, 0) != 1) + exit(1); + if (BIT(0x80000000, 31) != 1) + exit(2); + if (BITS(0xc0000000, 31, 30) != 3) + exit(3); +} + +/* + * EagleLake registers + */ +#define AUD_CONFIG 0x62000 +#define AUD_DEBUG 0x62010 +#define AUD_VID_DID 0x62020 +#define AUD_RID 0x62024 +#define AUD_SUBN_CNT 0x62028 +#define AUD_FUNC_GRP 0x62040 +#define AUD_SUBN_CNT2 0x62044 +#define AUD_GRP_CAP 0x62048 +#define AUD_PWRST 0x6204c +#define AUD_SUPPWR 0x62050 +#define AUD_SID 0x62054 +#define AUD_OUT_CWCAP 0x62070 +#define AUD_OUT_PCMSIZE 0x62074 +#define AUD_OUT_STR 0x62078 +#define AUD_OUT_DIG_CNVT 0x6207c +#define AUD_OUT_CH_STR 0x62080 +#define AUD_OUT_STR_DESC 0x62084 +#define AUD_PINW_CAP 0x620a0 +#define AUD_PIN_CAP 0x620a4 +#define AUD_PINW_CONNLNG 0x620a8 +#define AUD_PINW_CONNLST 0x620ac +#define AUD_PINW_CNTR 0x620b0 +#define AUD_PINW_UNSOLRESP 0x620b8 +#define AUD_CNTL_ST 0x620b4 +#define AUD_PINW_CONFIG 0x620bc +#define AUD_HDMIW_STATUS 0x620d4 +#define AUD_HDMIW_HDMIEDID 0x6210c +#define AUD_HDMIW_INFOFR 0x62118 +#define AUD_CONV_CHCNT 0x62120 +#define AUD_CTS_ENABLE 0x62128 + +#define VIDEO_DIP_CTL 0x61170 +#define VIDEO_DIP_ENABLE (1<<31) +#define VIDEO_DIP_ENABLE_AVI (1<<21) +#define VIDEO_DIP_ENABLE_VENDOR (1<<22) +#define VIDEO_DIP_ENABLE_SPD (1<<24) +#define VIDEO_DIP_BUF_AVI (0<<19) +#define VIDEO_DIP_BUF_VENDOR (1<<19) +#define VIDEO_DIP_BUF_SPD (3<<19) +#define VIDEO_DIP_TRANS_ONCE (0<<16) +#define VIDEO_DIP_TRANS_1 (1<<16) +#define VIDEO_DIP_TRANS_2 (2<<16) + +#define AUDIO_HOTPLUG_EN (1<<24) + + +static void dump_eaglelake(void) +{ + uint32_t dword; + int i; + + /* printf("%-18s %8s %s\n\n", "register name", "raw value", "description"); */ + + dump_reg(VIDEO_DIP_CTL, "Video DIP Control"); + dump_reg(SDVOB, "Digital Display Port B Control Register"); + dump_reg(SDVOC, "Digital Display Port C Control Register"); + dump_reg(PORT_HOTPLUG_EN, "Hot Plug Detect Enable"); + + dump_reg(AUD_CONFIG, "Audio Configuration"); + dump_reg(AUD_DEBUG, "Audio Debug"); + dump_reg(AUD_VID_DID, "Audio Vendor ID / Device ID"); + dump_reg(AUD_RID, "Audio Revision ID"); + dump_reg(AUD_SUBN_CNT, "Audio Subordinate Node Count"); + dump_reg(AUD_FUNC_GRP, "Audio Function Group Type"); + dump_reg(AUD_SUBN_CNT2, "Audio Subordinate Node Count"); + dump_reg(AUD_GRP_CAP, "Audio Function Group Capabilities"); + dump_reg(AUD_PWRST, "Audio Power State"); + dump_reg(AUD_SUPPWR, "Audio Supported Power States"); + dump_reg(AUD_SID, "Audio Root Node Subsystem ID"); + dump_reg(AUD_OUT_CWCAP, "Audio Output Converter Widget Capabilities"); + dump_reg(AUD_OUT_PCMSIZE, "Audio PCM Size and Rates"); + dump_reg(AUD_OUT_STR, "Audio Stream Formats"); + dump_reg(AUD_OUT_DIG_CNVT, "Audio Digital Converter"); + dump_reg(AUD_OUT_CH_STR, "Audio Channel ID and Stream ID"); + dump_reg(AUD_OUT_STR_DESC, "Audio Stream Descriptor Format"); + dump_reg(AUD_PINW_CAP, "Audio Pin Complex Widget Capabilities"); + dump_reg(AUD_PIN_CAP, "Audio Pin Capabilities"); + dump_reg(AUD_PINW_CONNLNG, "Audio Connection List Length"); + dump_reg(AUD_PINW_CONNLST, "Audio Connection List Entry"); + dump_reg(AUD_PINW_CNTR, "Audio Pin Widget Control"); + dump_reg(AUD_PINW_UNSOLRESP,"Audio Unsolicited Response Enable"); + dump_reg(AUD_CNTL_ST, "Audio Control State Register"); + dump_reg(AUD_PINW_CONFIG, "Audio Configuration Default"); + dump_reg(AUD_HDMIW_STATUS, "Audio HDMI Status"); + dump_reg(AUD_HDMIW_HDMIEDID,"Audio HDMI Data EDID Block"); + dump_reg(AUD_HDMIW_INFOFR, "Audio HDMI Widget Data Island Packet"); + dump_reg(AUD_CONV_CHCNT, "Audio Converter Channel Count"); + dump_reg(AUD_CTS_ENABLE, "Audio CTS Programming Enable"); + + printf("\nDetails:\n\n"); + + dword = INREG(AUD_VID_DID); + printf("AUD_VID_DID vendor id\t\t\t0x%x\n", dword >> 16); + printf("AUD_VID_DID device id\t\t\t0x%x\n", dword & 0xffff); + + dword = INREG(AUD_RID); + printf("AUD_RID major revision\t\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_RID minor revision\t\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_RID revision id\t\t\t0x%lx\n", BITS(dword, 15, 8)); + printf("AUD_RID stepping id\t\t\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(SDVOB); + printf("SDVOB enable\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("SDVOB HDMI encoding\t\t\t%u\n", !!(dword & SDVO_ENCODING_HDMI)); + printf("SDVOB SDVO encoding\t\t\t%u\n", !!(dword & SDVO_ENCODING_SDVO)); + printf("SDVOB null packets\t\t\t%u\n", !!(dword & SDVO_NULL_PACKETS_DURING_VSYNC)); + printf("SDVOB audio enabled\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(SDVOC); + printf("SDVOC enable\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("SDVOC HDMI encoding\t\t\t%u\n", !!(dword & SDVO_ENCODING_HDMI)); + printf("SDVOC SDVO encoding\t\t\t%u\n", !!(dword & SDVO_ENCODING_SDVO)); + printf("SDVOC null packets\t\t\t%u\n", !!(dword & SDVO_NULL_PACKETS_DURING_VSYNC)); + printf("SDVOC audio enabled\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(PORT_HOTPLUG_EN); + printf("PORT_HOTPLUG_EN DisplayPort/HDMI port B\t%ld\n", BIT(dword, 29)), + printf("PORT_HOTPLUG_EN DisplayPort/HDMI port C\t%ld\n", BIT(dword, 28)), + printf("PORT_HOTPLUG_EN DisplayPort port D\t%ld\n", BIT(dword, 27)), + printf("PORT_HOTPLUG_EN SDVOB\t\t\t%ld\n", BIT(dword, 26)), + printf("PORT_HOTPLUG_EN SDVOC\t\t\t%ld\n", BIT(dword, 25)), + printf("PORT_HOTPLUG_EN audio\t\t\t%ld\n", BIT(dword, 24)), + printf("PORT_HOTPLUG_EN TV\t\t\t%ld\n", BIT(dword, 23)), + printf("PORT_HOTPLUG_EN CRT\t\t\t%ld\n", BIT(dword, 9)), + + dword = INREG(VIDEO_DIP_CTL); + printf("VIDEO_DIP_CTL enable graphics DIP\t%ld\n", BIT(dword, 31)), + printf("VIDEO_DIP_CTL port select\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("VIDEO_DIP_CTL DIP buffer trans active\t%lu\n", BIT(dword, 28)); + printf("VIDEO_DIP_CTL AVI DIP enabled\t\t%lu\n", BIT(dword, 21)); + printf("VIDEO_DIP_CTL vendor DIP enabled\t%lu\n", BIT(dword, 22)); + printf("VIDEO_DIP_CTL SPD DIP enabled\t\t%lu\n", BIT(dword, 24)); + printf("VIDEO_DIP_CTL DIP buffer index\t\t[0x%lx] %s\n", + BITS(dword, 20, 19), video_dip_index[BITS(dword, 20, 19)]); + printf("VIDEO_DIP_CTL DIP trans freq\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), video_dip_trans[BITS(dword, 17, 16)]); + printf("VIDEO_DIP_CTL DIP buffer size\t\t%lu\n", BITS(dword, 11, 8)); + printf("VIDEO_DIP_CTL DIP address\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(AUD_CONFIG); + printf("AUD_CONFIG pixel clock\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG fabrication enabled\t\t%lu\n", BITS(dword, 2, 2)); + printf("AUD_CONFIG professional use allowed\t%lu\n", BIT(dword, 1)); + printf("AUD_CONFIG fuse enabled\t\t\t%lu\n", BIT(dword, 0)); + + dword = INREG(AUD_DEBUG); + printf("AUD_DEBUG function reset\t\t%lu\n", BIT(dword, 0)); + + dword = INREG(AUD_SUBN_CNT); + printf("AUD_SUBN_CNT starting node number\t0x%lx\n", BITS(dword, 23, 16)); + printf("AUD_SUBN_CNT total number of nodes\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(AUD_SUBN_CNT2); + printf("AUD_SUBN_CNT2 starting node number\t0x%lx\n", BITS(dword, 24, 16)); + printf("AUD_SUBN_CNT2 total number of nodes\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(AUD_FUNC_GRP); + printf("AUD_FUNC_GRP unsol capable\t\t%lu\n", BIT(dword, 8)); + printf("AUD_FUNC_GRP node type\t\t\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(AUD_GRP_CAP); + printf("AUD_GRP_CAP beep 0\t\t\t%lu\n", BIT(dword, 16)); + printf("AUD_GRP_CAP input delay\t\t\t%lu\n", BITS(dword, 11, 8)); + printf("AUD_GRP_CAP output delay\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(AUD_PWRST); + printf("AUD_PWRST device power state\t\t%s\n", + power_state[BITS(dword, 5, 4)]); + printf("AUD_PWRST device power state setting\t%s\n", + power_state[BITS(dword, 1, 0)]); + + dword = INREG(AUD_SUPPWR); + printf("AUD_SUPPWR support D0\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_SUPPWR support D1\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_SUPPWR support D2\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_SUPPWR support D3\t\t\t%lu\n", BIT(dword, 3)); + + dword = INREG(AUD_OUT_CWCAP); + printf("AUD_OUT_CWCAP widget type\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_OUT_CWCAP sample delay\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_OUT_CWCAP channel count\t\t%lu\n", + BITS(dword, 15, 13) * 2 + BIT(dword, 0) + 1); + printf("AUD_OUT_CWCAP L-R swap\t\t\t%lu\n", BIT(dword, 11)); + printf("AUD_OUT_CWCAP power control\t\t%lu\n", BIT(dword, 10)); + printf("AUD_OUT_CWCAP digital\t\t\t%lu\n", BIT(dword, 9)); + printf("AUD_OUT_CWCAP conn list\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_OUT_CWCAP unsol\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_CWCAP mute\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_CWCAP format override\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_CWCAP amp param override\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_CWCAP out amp present\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_CWCAP in amp present\t\t%lu\n", BIT(dword, 1)); + + dword = INREG(AUD_OUT_DIG_CNVT); + printf("AUD_OUT_DIG_CNVT SPDIF category\t\t0x%lx\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT SPDIF level\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT professional\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT non PCM\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT copyright asserted\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT filter preemphasis\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT validity config\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT validity flag\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT digital enable\t\t%lu\n", BIT(dword, 0)); + + dword = INREG(AUD_OUT_CH_STR); + printf("AUD_OUT_CH_STR stream id\t\t0x%lx\n", BITS(dword, 7, 4)); + printf("AUD_OUT_CH_STR lowest channel\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC); + printf("AUD_OUT_STR_DESC stream channels\t%lu\n", BITS(dword, 3, 0) + 1); + printf("AUD_OUT_STR_DESC Bits per Sample\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + + dword = INREG(AUD_PINW_CAP); + printf("AUD_PINW_CAP widget type\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_PINW_CAP sample delay\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_PINW_CAP channel count\t\t%lu\n", + BITS(dword, 15, 13) * 2 + BIT(dword, 0) + 1); + printf("AUD_PINW_CAP HDCP\t\t\t%lu\n", BIT(dword, 12)); + printf("AUD_PINW_CAP L-R swap\t\t\t%lu\n", BIT(dword, 11)); + printf("AUD_PINW_CAP power control\t\t%lu\n", BIT(dword, 10)); + printf("AUD_PINW_CAP digital\t\t\t%lu\n", BIT(dword, 9)); + printf("AUD_PINW_CAP conn list\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_PINW_CAP unsol\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_PINW_CAP mute\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_PINW_CAP format override\t\t%lu\n", BIT(dword, 4)); + printf("AUD_PINW_CAP amp param override\t\t%lu\n", BIT(dword, 3)); + printf("AUD_PINW_CAP out amp present\t\t%lu\n", BIT(dword, 2)); + printf("AUD_PINW_CAP in amp present\t\t%lu\n", BIT(dword, 1)); + + + dword = INREG(AUD_PIN_CAP); + printf("AUD_PIN_CAP EAPD\t\t\t%lu\n", BIT(dword, 16)); + printf("AUD_PIN_CAP HDMI\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_PIN_CAP output\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_PIN_CAP presence detect\t\t%lu\n", BIT(dword, 2)); + + dword = INREG(AUD_PINW_CNTR); + printf("AUD_PINW_CNTR mute status\t\t%lu\n", BIT(dword, 8)); + printf("AUD_PINW_CNTR out enable\t\t%lu\n", BIT(dword, 6)); + printf("AUD_PINW_CNTR amp mute status\t\t%lu\n", BIT(dword, 8)); + printf("AUD_PINW_CNTR amp mute status\t\t%lu\n", BIT(dword, 8)); + printf("AUD_PINW_CNTR stream type\t\t[0x%lx] %s\n", + BITS(dword, 2, 0), + OPNAME(stream_type, BITS(dword, 2, 0))); + + dword = INREG(AUD_PINW_UNSOLRESP); + printf("AUD_PINW_UNSOLRESP enable unsol resp\t%lu\n", BIT(dword, 31)); + + dword = INREG(AUD_CNTL_ST); + printf("AUD_CNTL_ST DIP audio enabled\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST DIP ACP enabled\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST DIP ISRCx enabled\t\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST DIP port select\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST DIP buffer index\t\t[0x%lx] %s\n", + BITS(dword, 20, 18), OPNAME(dip_index, BITS(dword, 20, 18))); + printf("AUD_CNTL_ST DIP trans freq\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST DIP address\t\t\t%lu\n", BITS(dword, 3, 0)); + printf("AUD_CNTL_ST CP ready\t\t\t%lu\n", BIT(dword, 15)); + printf("AUD_CNTL_ST ELD valid\t\t\t%lu\n", BIT(dword, 14)); + printf("AUD_CNTL_ST ELD ack\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST ELD bufsize\t\t\t%lu\n", BITS(dword, 13, 9)); + printf("AUD_CNTL_ST ELD address\t\t\t%lu\n", BITS(dword, 8, 5)); + + dword = INREG(AUD_HDMIW_STATUS); + printf("AUD_HDMIW_STATUS CDCLK/DOTCLK underrun\t%lu\n", BIT(dword, 31)); + printf("AUD_HDMIW_STATUS CDCLK/DOTCLK overrun\t%lu\n", BIT(dword, 30)); + printf("AUD_HDMIW_STATUS BCLK/CDCLK underrun\t%lu\n", BIT(dword, 29)); + printf("AUD_HDMIW_STATUS BCLK/CDCLK overrun\t%lu\n", BIT(dword, 28)); + + dword = INREG(AUD_CONV_CHCNT); + printf("AUD_CONV_CHCNT HDMI HBR enabled\t\t%lu\n", BITS(dword, 15, 14)); + printf("AUD_CONV_CHCNT HDMI channel count\t%lu\n", BITS(dword, 11, 8) + 1); + + printf("AUD_CONV_CHCNT HDMI channel mapping:\n"); + for (i = 0; i < 8; i++) { + OUTREG(AUD_CONV_CHCNT, i); + dword = INREG(AUD_CONV_CHCNT); + printf("\t\t\t\t\t[0x%x] %u => %lu \n", dword, i, BITS(dword, 7, 4)); + } + + printf("AUD_HDMIW_HDMIEDID HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST); + dword &= ~BITMASK(8, 5); + OUTREG(AUD_CNTL_ST, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR))); + printf("\n"); +} + +#undef AUD_RID +#undef AUD_VID_DID +#undef AUD_PWRST +#undef AUD_OUT_CH_STR +#undef AUD_HDMIW_STATUS + +/* + * IronLake registers + */ +#define AUD_CONFIG_A 0xE2000 +#define AUD_CONFIG_B 0xE2100 +#define AUD_CTS_ENABLE_A 0xE2028 +#define AUD_CTS_ENABLE_B 0xE2128 +#define AUD_MISC_CTRL_A 0xE2010 +#define AUD_MISC_CTRL_B 0xE2110 +#define AUD_VID_DID 0xE2020 +#define AUD_RID 0xE2024 +#define AUD_PWRST 0xE204C +#define AUD_PORT_EN_HD_CFG 0xE207C +#define AUD_OUT_DIG_CNVT_A 0xE2080 +#define AUD_OUT_DIG_CNVT_B 0xE2180 +#define AUD_OUT_CH_STR 0xE2088 +#define AUD_OUT_STR_DESC_A 0xE2084 +#define AUD_OUT_STR_DESC_B 0xE2184 +#define AUD_PINW_CONNLNG_LIST 0xE20A8 +#define AUD_PINW_CONNLNG_SEL 0xE20AC +#define AUD_CNTL_ST_A 0xE20B4 +#define AUD_CNTL_ST_B 0xE21B4 +#define AUD_CNTL_ST2 0xE20C0 +#define AUD_HDMIW_STATUS 0xE20D4 +#define AUD_HDMIW_HDMIEDID_A 0xE2050 +#define AUD_HDMIW_HDMIEDID_B 0xE2150 +#define AUD_HDMIW_INFOFR_A 0xE2054 +#define AUD_HDMIW_INFOFR_B 0xE2154 + +static void dump_ironlake(void) +{ + uint32_t dword; + int i; + + dump_reg(HDMIB, "sDVO/HDMI Port B Control"); + dump_reg(HDMIC, "HDMI Port C Control"); + dump_reg(HDMID, "HDMI Port D Control"); + dump_reg(PCH_DP_B, "DisplayPort B Control Register"); + dump_reg(PCH_DP_C, "DisplayPort C Control Register"); + dump_reg(PCH_DP_D, "DisplayPort D Control Register"); + dump_reg(AUD_CONFIG_A, "Audio Configuration - Transcoder A"); + dump_reg(AUD_CONFIG_B, "Audio Configuration - Transcoder B"); + dump_reg(AUD_CTS_ENABLE_A, "Audio CTS Programming Enable - Transcoder A"); + dump_reg(AUD_CTS_ENABLE_B, "Audio CTS Programming Enable - Transcoder B"); + dump_reg(AUD_MISC_CTRL_A, "Audio MISC Control for Transcoder A"); + dump_reg(AUD_MISC_CTRL_B, "Audio MISC Control for Transcoder B"); + dump_reg(AUD_VID_DID, "Audio Vendor ID / Device ID"); + dump_reg(AUD_RID, "Audio Revision ID"); + dump_reg(AUD_PWRST, "Audio Power State (Function Group, Convertor, Pin Widget)"); + dump_reg(AUD_PORT_EN_HD_CFG, "Audio Port Enable HDAudio Config"); + dump_reg(AUD_OUT_DIG_CNVT_A, "Audio Digital Converter - Conv A"); + dump_reg(AUD_OUT_DIG_CNVT_B, "Audio Digital Converter - Conv B"); + dump_reg(AUD_OUT_CH_STR, "Audio Channel ID and Stream ID"); + dump_reg(AUD_OUT_STR_DESC_A, "Audio Stream Descriptor Format - Conv A"); + dump_reg(AUD_OUT_STR_DESC_B, "Audio Stream Descriptor Format - Conv B"); + dump_reg(AUD_PINW_CONNLNG_LIST, "Audio Connection List"); + dump_reg(AUD_PINW_CONNLNG_SEL, "Audio Connection Select"); + dump_reg(AUD_CNTL_ST_A, "Audio Control State Register - Transcoder A"); + dump_reg(AUD_CNTL_ST_B, "Audio Control State Register - Transcoder B"); + dump_reg(AUD_CNTL_ST2, "Audio Control State 2"); + dump_reg(AUD_HDMIW_STATUS, "Audio HDMI Status"); + dump_reg(AUD_HDMIW_HDMIEDID_A, "HDMI Data EDID Block - Transcoder A"); + dump_reg(AUD_HDMIW_HDMIEDID_B, "HDMI Data EDID Block - Transcoder B"); + dump_reg(AUD_HDMIW_INFOFR_A, "Audio Widget Data Island Packet - Transcoder A"); + dump_reg(AUD_HDMIW_INFOFR_B, "Audio Widget Data Island Packet - Transcoder B"); + + printf("\nDetails:\n\n"); + + dword = INREG(AUD_VID_DID); + printf("AUD_VID_DID vendor id\t\t\t\t\t0x%x\n", dword >> 16); + printf("AUD_VID_DID device id\t\t\t\t\t0x%x\n", dword & 0xffff); + + dword = INREG(AUD_RID); + printf("AUD_RID Major_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_RID Minor_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_RID Revision_Id\t\t\t\t\t0x%lx\n", BITS(dword, 15, 8)); + printf("AUD_RID Stepping_Id\t\t\t\t\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(HDMIB); + printf("HDMIB HDMIB_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMIB Transcoder_Select\t\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("HDMIB HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMIB SDVOB Hot Plug Interrupt Detect Enable\t\t%lu\n", BIT(dword, 23)); + printf("HDMIB Digital_Port_B_Detected\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMIB Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMIB Null_packets_enabled_during_Vsync\t\t\t%u\n", !!(dword & SDVO_NULL_PACKETS_DURING_VSYNC)); + printf("HDMIB Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(HDMIC); + printf("HDMIC HDMIC_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMIC Transcoder_Select\t\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("HDMIC HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMIC Digital_Port_C_Detected\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMIC Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMIC Null_packets_enabled_during_Vsync\t\t\t%u\n", !!(dword & SDVO_NULL_PACKETS_DURING_VSYNC)); + printf("HDMIC Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(HDMID); + printf("HDMID HDMID_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMID Transcoder_Select\t\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("HDMID HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMID Digital_Port_D_Detected\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMID Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMID Null_packets_enabled_during_Vsync\t\t\t%u\n", !!(dword & SDVO_NULL_PACKETS_DURING_VSYNC)); + printf("HDMID Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(PCH_DP_B); + printf("PCH_DP_B DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("PCH_DP_B Transcoder_Select\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("PCH_DP_B Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("PCH_DP_B Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("PCH_DP_B HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("PCH_DP_B Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(PCH_DP_C); + printf("PCH_DP_C DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("PCH_DP_C Transcoder_Select\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("PCH_DP_C Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("PCH_DP_C Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("PCH_DP_C HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("PCH_DP_C Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(PCH_DP_D); + printf("PCH_DP_D DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("PCH_DP_D Transcoder_Select\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("PCH_DP_D Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("PCH_DP_D Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("PCH_DP_D HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("PCH_DP_D Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(AUD_CONFIG_A); + printf("AUD_CONFIG_A N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_A N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_A Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_A Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_A Pixel_Clock\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_A Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + dword = INREG(AUD_CONFIG_B); + printf("AUD_CONFIG_B N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_B N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_B Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_B Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_B Pixel_Clock\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_B Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + + dword = INREG(AUD_CTS_ENABLE_A); + printf("AUD_CTS_ENABLE_A Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_A CTS/M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_A CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + dword = INREG(AUD_CTS_ENABLE_B); + printf("AUD_CTS_ENABLE_B Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_B CTS/M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_B CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + + dword = INREG(AUD_MISC_CTRL_A); + printf("AUD_MISC_CTRL_A Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_A Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_A Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_A Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + dword = INREG(AUD_MISC_CTRL_B); + printf("AUD_MISC_CTRL_B Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_B Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_B Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_B Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + + dword = INREG(AUD_PWRST); + printf("AUD_PWRST Function_Group_Device_Power_State_Current\t%s\n", power_state[BITS(dword, 23, 22)]); + printf("AUD_PWRST Function_Group_Device_Power_State_Set \t%s\n", power_state[BITS(dword, 21, 20)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 19, 18)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Requested \t%s\n", power_state[BITS(dword, 17, 16)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 15, 14)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Requsted \t%s\n", power_state[BITS(dword, 13, 12)]); + printf("AUD_PWRST PinD_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 11, 10)]); + printf("AUD_PWRST PinD_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 9, 8)]); + printf("AUD_PWRST PinC_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 7, 6)]); + printf("AUD_PWRST PinC_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 5, 4)]); + printf("AUD_PWRST PinB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 3, 2)]); + printf("AUD_PWRST PinB_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 1, 0)]); + + dword = INREG(AUD_PORT_EN_HD_CFG); + printf("AUD_PORT_EN_HD_CFG Convertor_A_Digen\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_PORT_EN_HD_CFG Convertor_B_Digen\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_PORT_EN_HD_CFG ConvertorA_Stream_ID\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_PORT_EN_HD_CFG ConvertorB_Stream_ID\t\t%lu\n", BITS(dword, 11, 8)); + printf("AUD_PORT_EN_HD_CFG Port_B_Out_Enable\t\t\t%lu\n", BIT(dword, 12)); + printf("AUD_PORT_EN_HD_CFG Port_C_Out_Enable\t\t\t%lu\n", BIT(dword, 13)); + printf("AUD_PORT_EN_HD_CFG Port_D_Out_Enable\t\t\t%lu\n", BIT(dword, 14)); + printf("AUD_PORT_EN_HD_CFG Port_B_Amp_Mute_Status\t\t%lu\n", BIT(dword, 16)); + printf("AUD_PORT_EN_HD_CFG Port_C_Amp_Mute_Status\t\t%lu\n", BIT(dword, 17)); + printf("AUD_PORT_EN_HD_CFG Port_D_Amp_Mute_Status\t\t%lu\n", BIT(dword, 18)); + + dword = INREG(AUD_OUT_DIG_CNVT_A); + printf("AUD_OUT_DIG_CNVT_A V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_A VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_A PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_A Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_A NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_A PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_A Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_A Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_A Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_A Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + dword = INREG(AUD_OUT_DIG_CNVT_B); + printf("AUD_OUT_DIG_CNVT_B V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_B VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_B PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_B Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_B NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_B PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_B Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_B Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_B Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_B Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + printf("AUD_OUT_CH_STR Converter_Channel_MAP PORTB PORTC PORTD\n"); + for (i = 0; i < 8; i++) { + OUTREG(AUD_OUT_CH_STR, i | (i << 8) | (i << 16)); + dword = INREG(AUD_OUT_CH_STR); + printf("\t\t\t\t%lu\t%lu\t%lu\t%lu\n", + 1 + BITS(dword, 3, 0), + 1 + BITS(dword, 7, 4), + 1 + BITS(dword, 15, 12), + 1 + BITS(dword, 23, 20)); + } + + dword = INREG(AUD_OUT_STR_DESC_A); + printf("AUD_OUT_STR_DESC_A HBR_enable\t\t\t\t%lu\n", BITS(dword, 28, 27)); + printf("AUD_OUT_STR_DESC_A Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_A Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_A Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC_B); + printf("AUD_OUT_STR_DESC_B HBR_enable\t\t\t\t%lu\n", BITS(dword, 28, 27)); + printf("AUD_OUT_STR_DESC_B Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_B Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_B Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_PINW_CONNLNG_SEL); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_B\t%lu\n", BITS(dword, 7, 0)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_C\t%lu\n", BITS(dword, 15, 8)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_D\t%lu\n", BITS(dword, 23, 16)); + + dword = INREG(AUD_CNTL_ST_A); + printf("AUD_CNTL_ST_A DIP_Port_Select\t\t\t\t[%#lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST_A DIP_type_enable_status Audio DIP\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST_A DIP_type_enable_status ACP DIP\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST_A DIP_type_enable_status Generic 2 DIP\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST_A DIP_transmission_frequency\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST_A ELD_ACK\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST_A ELD_buffer_size\t\t\t\t%lu\n", BITS(dword, 14, 10)); + printf("AUD_CNTL_ST_A ELD_access_address\t\t\t%lu\n", BITS(dword, 9, 5)); + + dword = INREG(AUD_CNTL_ST_B); + printf("AUD_CNTL_ST_B DIP_Port_Select\t\t\t\t[%#lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST_B DIP_type_enable_status Audio DIP\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST_B DIP_type_enable_status ACP DIP\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST_B DIP_type_enable_status Generic 2 DIP\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST_B DIP_transmission_frequency\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST_B ELD_ACK\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST_B ELD_buffer_size\t\t\t\t%lu\n", BITS(dword, 14, 10)); + printf("AUD_CNTL_ST_B ELD_access_address\t\t\t%lu\n", BITS(dword, 9, 5)); + + dword = INREG(AUD_CNTL_ST2); + printf("AUD_CNTL_ST2 CP_ReadyB\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_CNTL_ST2 ELD_validB\t\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_CNTL_ST2 CP_ReadyC\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_CNTL_ST2 ELD_validC\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST2 CP_ReadyD\t\t\t\t\t%lu\n", BIT(dword, 9)); + printf("AUD_CNTL_ST2 ELD_validD\t\t\t\t%lu\n", BIT(dword, 8)); + + dword = INREG(AUD_HDMIW_STATUS); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 31)); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 30)); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 29)); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 28)); + printf("AUD_HDMIW_STATUS BCLK/CDCLK_FIFO_Overrun\t\t%lu\n", BIT(dword, 25)); + printf("AUD_HDMIW_STATUS Function_Reset\t\t\t%lu\n", BIT(dword, 29)); + + printf("AUD_HDMIW_HDMIEDID_A HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST_A); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_CNTL_ST_A, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_A))); + printf("\n"); + + printf("AUD_HDMIW_HDMIEDID_B HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST_B); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_CNTL_ST_B, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_B))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_A HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST_A); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST_A, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_A))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_B HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST_B); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST_B, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_B))); + printf("\n"); + +} + + +#undef AUD_CONFIG_A +#undef AUD_MISC_CTRL_A +#undef AUD_VID_DID +#undef AUD_RID +#undef AUD_CTS_ENABLE_A +#undef AUD_PWRST +#undef AUD_HDMIW_HDMIEDID_A +#undef AUD_HDMIW_INFOFR_A +#undef AUD_PORT_EN_HD_CFG +#undef AUD_OUT_DIG_CNVT_A +#undef AUD_OUT_STR_DESC_A +#undef AUD_OUT_CH_STR +#undef AUD_PINW_CONNLNG_LIST +#undef AUD_CNTL_ST_A +#undef AUD_HDMIW_STATUS +#undef AUD_CONFIG_B +#undef AUD_MISC_CTRL_B +#undef AUD_CTS_ENABLE_B +#undef AUD_HDMIW_HDMIEDID_B +#undef AUD_HDMIW_INFOFR_B +#undef AUD_OUT_DIG_CNVT_B +#undef AUD_OUT_STR_DESC_B +#undef AUD_CNTL_ST_B + +/* + * CougarPoint registers + */ +#define DP_CTL_B 0xE4100 +#define DP_CTL_C 0xE4200 +#define DP_AUX_CTL_C 0xE4210 +#define DP_AUX_TST_C 0xE4228 +#define SPORT_DDI_CRC_C 0xE4250 +#define SPORT_DDI_CRC_R 0xE4264 +#define DP_CTL_D 0xE4300 +#define DP_AUX_CTL_D 0xE4310 +#define DP_AUX_TST_D 0xE4328 +#define SPORT_DDI_CRC_CTL_D 0xE4350 +#define AUD_CONFIG_A 0xE5000 +#define AUD_MISC_CTRL_A 0xE5010 +#define AUD_VID_DID 0xE5020 +#define AUD_RID 0xE5024 +#define AUD_CTS_ENABLE_A 0xE5028 +#define AUD_PWRST 0xE504C +#define AUD_HDMIW_HDMIEDID_A 0xE5050 +#define AUD_HDMIW_INFOFR_A 0xE5054 +#define AUD_PORT_EN_HD_CFG 0xE507C +#define AUD_OUT_DIG_CNVT_A 0xE5080 +#define AUD_OUT_STR_DESC_A 0xE5084 +#define AUD_OUT_CH_STR 0xE5088 +#define AUD_PINW_CONNLNG_LIST 0xE50A8 +#define AUD_PINW_CONNLNG_SELA 0xE50AC +#define AUD_CNTL_ST_A 0xE50B4 +#define AUD_CNTRL_ST2 0xE50C0 +#define AUD_CNTRL_ST3 0xE50C4 +#define AUD_HDMIW_STATUS 0xE50D4 +#define AUD_CONFIG_B 0xE5100 +#define AUD_MISC_CTRL_B 0xE5110 +#define AUD_CTS_ENABLE_B 0xE5128 +#define AUD_HDMIW_HDMIEDID_B 0xE5150 +#define AUD_HDMIW_INFOFR_B 0xE5154 +#define AUD_OUT_DIG_CNVT_B 0xE5180 +#define AUD_OUT_STR_DESC_B 0xE5184 +#define AUD_CNTL_ST_B 0xE51B4 +#define AUD_CONFIG_C 0xE5200 +#define AUD_MISC_CTRL_C 0xE5210 +#define AUD_CTS_ENABLE_C 0xE5228 +#define AUD_HDMIW_HDMIEDID_C 0xE5250 +#define AUD_HDMIW_INFOFR_C 0xE5254 +#define AUD_OUT_DIG_CNVT_C 0xE5280 +#define AUD_OUT_STR_DESC_C 0xE5284 +#define AUD_CNTL_ST_C 0xE52B4 +#define AUD_CONFIG_D 0xE5300 +#define AUD_MISC_CTRL_D 0xE5310 +#define AUD_CTS_ENABLE_D 0xE5328 +#define AUD_HDMIW_HDMIEDID_D 0xE5350 +#define AUD_HDMIW_INFOFR_D 0xE5354 +#define AUD_OUT_DIG_CNVT_D 0xE5380 +#define AUD_OUT_STR_DESC_D 0xE5384 +#define AUD_CNTL_ST_D 0xE53B4 + +#define VIDEO_DIP_CTL_A 0xE0200 +#define VIDEO_DIP_CTL_B 0xE1200 +#define VIDEO_DIP_CTL_C 0xE2200 +#define VIDEO_DIP_CTL_D 0xE3200 + + +static void dump_cpt(void) +{ + uint32_t dword; + int i; + + dump_reg(HDMIB, "sDVO/HDMI Port B Control"); + dump_reg(HDMIC, "HDMI Port C Control"); + dump_reg(HDMID, "HDMI Port D Control"); + dump_reg(DP_CTL_B, "DisplayPort B Control"); + dump_reg(DP_CTL_C, "DisplayPort C Control"); + dump_reg(DP_CTL_D, "DisplayPort D Control"); + dump_reg(TRANS_DP_CTL_A, "Transcoder A DisplayPort Control"); + dump_reg(TRANS_DP_CTL_B, "Transcoder B DisplayPort Control"); + dump_reg(TRANS_DP_CTL_C, "Transcoder C DisplayPort Control"); + dump_reg(AUD_CONFIG_A, "Audio Configuration - Transcoder A"); + dump_reg(AUD_CONFIG_B, "Audio Configuration - Transcoder B"); + dump_reg(AUD_CONFIG_C, "Audio Configuration - Transcoder C"); + dump_reg(AUD_CTS_ENABLE_A, "Audio CTS Programming Enable - Transcoder A"); + dump_reg(AUD_CTS_ENABLE_B, "Audio CTS Programming Enable - Transcoder B"); + dump_reg(AUD_CTS_ENABLE_C, "Audio CTS Programming Enable - Transcoder C"); + dump_reg(AUD_MISC_CTRL_A, "Audio MISC Control for Transcoder A"); + dump_reg(AUD_MISC_CTRL_B, "Audio MISC Control for Transcoder B"); + dump_reg(AUD_MISC_CTRL_C, "Audio MISC Control for Transcoder C"); + dump_reg(AUD_VID_DID, "Audio Vendor ID / Device ID"); + dump_reg(AUD_RID, "Audio Revision ID"); + dump_reg(AUD_PWRST, "Audio Power State (Function Group, Convertor, Pin Widget)"); + dump_reg(AUD_PORT_EN_HD_CFG, "Audio Port Enable HDAudio Config"); + dump_reg(AUD_OUT_DIG_CNVT_A, "Audio Digital Converter - Conv A"); + dump_reg(AUD_OUT_DIG_CNVT_B, "Audio Digital Converter - Conv B"); + dump_reg(AUD_OUT_DIG_CNVT_C, "Audio Digital Converter - Conv C"); + dump_reg(AUD_OUT_CH_STR, "Audio Channel ID and Stream ID"); + dump_reg(AUD_OUT_STR_DESC_A, "Audio Stream Descriptor Format - Conv A"); + dump_reg(AUD_OUT_STR_DESC_B, "Audio Stream Descriptor Format - Conv B"); + dump_reg(AUD_OUT_STR_DESC_C, "Audio Stream Descriptor Format - Conv C"); + dump_reg(AUD_PINW_CONNLNG_LIST, "Audio Connection List"); + dump_reg(AUD_PINW_CONNLNG_SEL, "Audio Connection Select"); + dump_reg(AUD_CNTL_ST_A, "Audio Control State Register - Transcoder A"); + dump_reg(AUD_CNTL_ST_B, "Audio Control State Register - Transcoder B"); + dump_reg(AUD_CNTL_ST_C, "Audio Control State Register - Transcoder C"); + dump_reg(AUD_CNTRL_ST2, "Audio Control State 2"); + dump_reg(AUD_CNTRL_ST3, "Audio Control State 3"); + dump_reg(AUD_HDMIW_STATUS, "Audio HDMI Status"); + dump_reg(AUD_HDMIW_HDMIEDID_A, "HDMI Data EDID Block - Transcoder A"); + dump_reg(AUD_HDMIW_HDMIEDID_B, "HDMI Data EDID Block - Transcoder B"); + dump_reg(AUD_HDMIW_HDMIEDID_C, "HDMI Data EDID Block - Transcoder C"); + dump_reg(AUD_HDMIW_INFOFR_A, "Audio Widget Data Island Packet - Transcoder A"); + dump_reg(AUD_HDMIW_INFOFR_B, "Audio Widget Data Island Packet - Transcoder B"); + dump_reg(AUD_HDMIW_INFOFR_C, "Audio Widget Data Island Packet - Transcoder C"); + + printf("\nDetails:\n\n"); + + dword = INREG(VIDEO_DIP_CTL_A); + printf("VIDEO_DIP_CTL_A Enable_Graphics_DIP\t\t\t%ld\n", BIT(dword, 31)), + printf("VIDEO_DIP_CTL_A GCP_DIP_enable\t\t\t\t%ld\n", BIT(dword, 25)), + printf("VIDEO_DIP_CTL_A Video_DIP_type_enable AVI\t\t%lu\n", BIT(dword, 21)); + printf("VIDEO_DIP_CTL_A Video_DIP_type_enable Vendor\t\t%lu\n", BIT(dword, 22)); + printf("VIDEO_DIP_CTL_A Video_DIP_type_enable Gamut\t\t%lu\n", BIT(dword, 23)); + printf("VIDEO_DIP_CTL_A Video_DIP_type_enable Source \t\t%lu\n", BIT(dword, 24)); + printf("VIDEO_DIP_CTL_A Video_DIP_buffer_index\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 19), video_dip_index[BITS(dword, 20, 19)]); + printf("VIDEO_DIP_CTL_A Video_DIP_frequency\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), video_dip_trans[BITS(dword, 17, 16)]); + printf("VIDEO_DIP_CTL_A Video_DIP_buffer_size\t\t\t%lu\n", BITS(dword, 11, 8)); + printf("VIDEO_DIP_CTL_A Video_DIP_access_address\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(VIDEO_DIP_CTL_B); + printf("VIDEO_DIP_CTL_B Enable_Graphics_DIP\t\t\t%ld\n", BIT(dword, 31)), + printf("VIDEO_DIP_CTL_B GCP_DIP_enable\t\t\t\t%ld\n", BIT(dword, 25)), + printf("VIDEO_DIP_CTL_B Video_DIP_type_enable AVI\t\t%lu\n", BIT(dword, 21)); + printf("VIDEO_DIP_CTL_B Video_DIP_type_enable Vendor\t\t%lu\n", BIT(dword, 22)); + printf("VIDEO_DIP_CTL_B Video_DIP_type_enable Gamut\t\t%lu\n", BIT(dword, 23)); + printf("VIDEO_DIP_CTL_B Video_DIP_type_enable Source \t\t%lu\n", BIT(dword, 24)); + printf("VIDEO_DIP_CTL_B Video_DIP_buffer_index\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 19), video_dip_index[BITS(dword, 20, 19)]); + printf("VIDEO_DIP_CTL_B Video_DIP_frequency\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), video_dip_trans[BITS(dword, 17, 16)]); + printf("VIDEO_DIP_CTL_B Video_DIP_buffer_size\t\t\t%lu\n", BITS(dword, 11, 8)); + printf("VIDEO_DIP_CTL_B Video_DIP_access_address\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(VIDEO_DIP_CTL_C); + printf("VIDEO_DIP_CTL_C Enable_Graphics_DIP\t\t\t%ld\n", BIT(dword, 31)), + printf("VIDEO_DIP_CTL_C GCP_DIP_enable\t\t\t\t%ld\n", BIT(dword, 25)), + printf("VIDEO_DIP_CTL_C Video_DIP_type_enable AVI\t\t%lu\n", BIT(dword, 21)); + printf("VIDEO_DIP_CTL_C Video_DIP_type_enable Vendor\t\t%lu\n", BIT(dword, 22)); + printf("VIDEO_DIP_CTL_C Video_DIP_type_enable Gamut\t\t%lu\n", BIT(dword, 23)); + printf("VIDEO_DIP_CTL_C Video_DIP_type_enable Source \t\t%lu\n", BIT(dword, 24)); + printf("VIDEO_DIP_CTL_C Video_DIP_buffer_index\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 19), video_dip_index[BITS(dword, 20, 19)]); + printf("VIDEO_DIP_CTL_C Video_DIP_frequency\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), video_dip_trans[BITS(dword, 17, 16)]); + printf("VIDEO_DIP_CTL_C Video_DIP_buffer_size\t\t\t%lu\n", BITS(dword, 11, 8)); + printf("VIDEO_DIP_CTL_C Video_DIP_access_address\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(AUD_VID_DID); + printf("AUD_VID_DID vendor id\t\t\t\t\t0x%x\n", dword >> 16); + printf("AUD_VID_DID device id\t\t\t\t\t0x%x\n", dword & 0xffff); + + dword = INREG(AUD_RID); + printf("AUD_RID Major_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_RID Minor_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_RID Revision_Id\t\t\t\t\t0x%lx\n", BITS(dword, 15, 8)); + printf("AUD_RID Stepping_Id\t\t\t\t\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(HDMIB); + printf("HDMIB Port_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMIB Transcoder_Select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), transcoder_select[BITS(dword, 30, 29)]); + printf("HDMIB sDVO_Border_Enable\t\t\t\t%lu\n", BIT(dword, 7)); + printf("HDMIB HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMIB SDVO_HPD_Interrupt_Enable\t\t\t\t%lu\n", BIT(dword, 23)); + printf("HDMIB Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMIB Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMIB HDMI_or_DVI_Select\t\t\t\t%s\n", BIT(dword, 9) ? "HDMI" : "DVI"); + printf("HDMIB Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(HDMIC); + printf("HDMIC Port_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMIC Transcoder_Select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), transcoder_select[BITS(dword, 30, 29)]); + printf("HDMIC sDVO_Border_Enable\t\t\t\t%lu\n", BIT(dword, 7)); + printf("HDMIC HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMIC SDVO_HPD_Interrupt_Enable\t\t\t\t%lu\n", BIT(dword, 23)); + printf("HDMIC Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMIC Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMIC HDMI_or_DVI_Select\t\t\t\t%s\n", BIT(dword, 9) ? "HDMI" : "DVI"); + printf("HDMIC Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(HDMID); + printf("HDMID Port_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMID Transcoder_Select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), transcoder_select[BITS(dword, 30, 29)]); + printf("HDMID sDVO_Border_Enable\t\t\t\t%lu\n", BIT(dword, 7)); + printf("HDMID HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMID SDVO_HPD_Interrupt_Enable\t\t\t\t%lu\n", BIT(dword, 23)); + printf("HDMID Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMID Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMID HDMI_or_DVI_Select\t\t\t\t%s\n", BIT(dword, 9) ? "HDMI" : "DVI"); + printf("HDMID Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(DP_CTL_B); + printf("DP_CTL_B DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("DP_CTL_B Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("DP_CTL_B Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("DP_CTL_B HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("DP_CTL_B Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(DP_CTL_C); + printf("DP_CTL_C DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("DP_CTL_C Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("DP_CTL_C Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("DP_CTL_C HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("DP_CTL_C Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(DP_CTL_D); + printf("DP_CTL_D DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("DP_CTL_D Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("DP_CTL_D Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("DP_CTL_D HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("DP_CTL_D Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(AUD_CONFIG_A); + printf("AUD_CONFIG_A N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_A N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_A Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_A Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_A Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_A Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + dword = INREG(AUD_CONFIG_B); + printf("AUD_CONFIG_B N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_B N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_B Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_B Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_B Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_B Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + dword = INREG(AUD_CONFIG_C); + printf("AUD_CONFIG_C N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_C N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_C Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_C Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_C Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_C Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + + dword = INREG(AUD_CTS_ENABLE_A); + printf("AUD_CTS_ENABLE_A Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_A CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_A CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + dword = INREG(AUD_CTS_ENABLE_B); + printf("AUD_CTS_ENABLE_B Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_B CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_B CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + dword = INREG(AUD_CTS_ENABLE_C); + printf("AUD_CTS_ENABLE_C Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_C CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_C CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + + dword = INREG(AUD_MISC_CTRL_A); + printf("AUD_MISC_CTRL_A Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_A Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_A Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_A Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + dword = INREG(AUD_MISC_CTRL_B); + printf("AUD_MISC_CTRL_B Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_B Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_B Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_B Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + dword = INREG(AUD_MISC_CTRL_C); + printf("AUD_MISC_CTRL_C Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_C Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_C Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_C Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + + dword = INREG(AUD_PWRST); + printf("AUD_PWRST Func_Grp_Dev_PwrSt_Curr \t%s\n", power_state[BITS(dword, 27, 26)]); + printf("AUD_PWRST Func_Grp_Dev_PwrSt_Set \t%s\n", power_state[BITS(dword, 25, 24)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 15, 14)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Requsted \t%s\n", power_state[BITS(dword, 13, 12)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 19, 18)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Requested \t%s\n", power_state[BITS(dword, 17, 16)]); + printf("AUD_PWRST ConvC_Widget_PwrSt_Curr \t%s\n", power_state[BITS(dword, 23, 22)]); + printf("AUD_PWRST ConvC_Widget_PwrSt_Req \t%s\n", power_state[BITS(dword, 21, 20)]); + printf("AUD_PWRST PinB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 3, 2)]); + printf("AUD_PWRST PinB_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 1, 0)]); + printf("AUD_PWRST PinC_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 7, 6)]); + printf("AUD_PWRST PinC_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 5, 4)]); + printf("AUD_PWRST PinD_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 11, 10)]); + printf("AUD_PWRST PinD_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 9, 8)]); + + dword = INREG(AUD_PORT_EN_HD_CFG); + printf("AUD_PORT_EN_HD_CFG Convertor_A_Digen\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_PORT_EN_HD_CFG Convertor_B_Digen\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_PORT_EN_HD_CFG Convertor_C_Digen\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_PORT_EN_HD_CFG ConvertorA_Stream_ID\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_PORT_EN_HD_CFG ConvertorB_Stream_ID\t\t%lu\n", BITS(dword, 11, 8)); + printf("AUD_PORT_EN_HD_CFG ConvertorC_Stream_ID\t\t%lu\n", BITS(dword, 15, 12)); + printf("AUD_PORT_EN_HD_CFG Port_B_Out_Enable\t\t\t%lu\n", BIT(dword, 16)); + printf("AUD_PORT_EN_HD_CFG Port_C_Out_Enable\t\t\t%lu\n", BIT(dword, 17)); + printf("AUD_PORT_EN_HD_CFG Port_D_Out_Enable\t\t\t%lu\n", BIT(dword, 18)); + printf("AUD_PORT_EN_HD_CFG Port_B_Amp_Mute_Status\t\t%lu\n", BIT(dword, 20)); + printf("AUD_PORT_EN_HD_CFG Port_C_Amp_Mute_Status\t\t%lu\n", BIT(dword, 21)); + printf("AUD_PORT_EN_HD_CFG Port_D_Amp_Mute_Status\t\t%lu\n", BIT(dword, 22)); + + dword = INREG(AUD_OUT_DIG_CNVT_A); + printf("AUD_OUT_DIG_CNVT_A V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_A VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_A PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_A Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_A NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_A PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_A Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_A Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_A Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_A Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + dword = INREG(AUD_OUT_DIG_CNVT_B); + printf("AUD_OUT_DIG_CNVT_B V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_B VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_B PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_B Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_B NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_B PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_B Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_B Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_B Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_B Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + dword = INREG(AUD_OUT_DIG_CNVT_C); + printf("AUD_OUT_DIG_CNVT_C V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_C VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_C PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_C Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_C NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_C PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_C Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_C Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_C Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_C Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + printf("AUD_OUT_CH_STR Converter_Channel_MAP PORTB PORTC PORTD\n"); + for (i = 0; i < 8; i++) { + OUTREG(AUD_OUT_CH_STR, i | (i << 8) | (i << 16)); + dword = INREG(AUD_OUT_CH_STR); + printf("\t\t\t\t%lu\t%lu\t%lu\t%lu\n", + 1 + BITS(dword, 3, 0), + 1 + BITS(dword, 7, 4), + 1 + BITS(dword, 15, 12), + 1 + BITS(dword, 23, 20)); + } + + dword = INREG(AUD_OUT_STR_DESC_A); + printf("AUD_OUT_STR_DESC_A HBR_enable\t\t\t\t%lu\n", BITS(dword, 28, 27)); + printf("AUD_OUT_STR_DESC_A Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_A Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_A Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC_B); + printf("AUD_OUT_STR_DESC_B HBR_enable\t\t\t\t%lu\n", BITS(dword, 28, 27)); + printf("AUD_OUT_STR_DESC_B Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_B Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_B Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC_C); + printf("AUD_OUT_STR_DESC_C HBR_enable\t\t\t\t%lu\n", BITS(dword, 28, 27)); + printf("AUD_OUT_STR_DESC_C Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_C Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_C Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_PINW_CONNLNG_SEL); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_B\t%#lx\n", BITS(dword, 7, 0)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_C\t%#lx\n", BITS(dword, 15, 8)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_D\t%#lx\n", BITS(dword, 23, 16)); + + dword = INREG(AUD_CNTL_ST_A); + printf("AUD_CNTL_ST_A DIP_Port_Select\t\t\t\t[%#lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST_A DIP_type_enable_status Audio DIP\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST_A DIP_type_enable_status ACP DIP\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST_A DIP_type_enable_status Generic 2 DIP\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST_A DIP_transmission_frequency\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST_A ELD_ACK\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST_A ELD_buffer_size\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(AUD_CNTL_ST_B); + printf("AUD_CNTL_ST_B DIP_Port_Select\t\t\t\t[%#lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST_B DIP_type_enable_status Audio DIP\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST_B DIP_type_enable_status ACP DIP\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST_B DIP_type_enable_status Generic 2 DIP\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST_B DIP_transmission_frequency\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST_B ELD_ACK\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST_B ELD_buffer_size\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(AUD_CNTL_ST_C); + printf("AUD_CNTL_ST_C DIP_Port_Select\t\t\t\t[%#lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST_C DIP_type_enable_status Audio DIP\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST_C DIP_type_enable_status ACP DIP\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST_C DIP_type_enable_status Generic 2 DIP\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST_C DIP_transmission_frequency\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST_C ELD_ACK\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST_C ELD_buffer_size\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(AUD_CNTRL_ST2); + printf("AUD_CNTRL_ST2 CP_ReadyB\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_CNTRL_ST2 ELD_validB\t\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_CNTRL_ST2 CP_ReadyC\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_CNTRL_ST2 ELD_validC\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTRL_ST2 CP_ReadyD\t\t\t\t%lu\n", BIT(dword, 9)); + printf("AUD_CNTRL_ST2 ELD_validD\t\t\t\t%lu\n", BIT(dword, 8)); + + dword = INREG(AUD_CNTRL_ST3); + printf("AUD_CNTRL_ST3 TransA_DPT_Audio_Output_En\t\t%lu\n", BIT(dword, 3)); + printf("AUD_CNTRL_ST3 TransA_to_Port_Sel\t\t\t[%#lx] %s\n", + BITS(dword, 2, 0), trans_to_port_sel[BITS(dword, 2, 0)]); + printf("AUD_CNTRL_ST3 TransB_DPT_Audio_Output_En\t\t%lu\n", BIT(dword, 7)); + printf("AUD_CNTRL_ST3 TransB_to_Port_Sel\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), trans_to_port_sel[BITS(dword, 6, 4)]); + printf("AUD_CNTRL_ST3 TransC_DPT_Audio_Output_En\t\t%lu\n", BIT(dword, 11)); + printf("AUD_CNTRL_ST3 TransC_to_Port_Sel\t\t\t[%#lx] %s\n", + BITS(dword, 10, 8), trans_to_port_sel[BITS(dword, 10, 8)]); + + dword = INREG(AUD_HDMIW_STATUS); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 27)); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 26)); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 29)); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 28)); + printf("AUD_HDMIW_STATUS Conv_C_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 31)); + printf("AUD_HDMIW_STATUS Conv_C_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 30)); + printf("AUD_HDMIW_STATUS BCLK/CDCLK_FIFO_Overrun\t\t%lu\n", BIT(dword, 25)); + printf("AUD_HDMIW_STATUS Function_Reset\t\t\t%lu\n", BIT(dword, 24)); + + printf("AUD_HDMIW_HDMIEDID_A HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST_A); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_CNTL_ST_A, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_A))); + printf("\n"); + + printf("AUD_HDMIW_HDMIEDID_B HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST_B); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_CNTL_ST_B, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_B))); + printf("\n"); + + printf("AUD_HDMIW_HDMIEDID_C HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST_C); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_CNTL_ST_C, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_C))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_A HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST_A); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST_A, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_A))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_B HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST_B); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST_B, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_B))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_C HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST_C); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST_C, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_C))); + printf("\n"); + +} + +#undef AUD_CONFIG_A +#undef AUD_MISC_CTRL_A +#undef AUD_VID_DID +#undef AUD_RID +#undef AUD_CTS_ENABLE_A +#undef AUD_PWRST +#undef AUD_HDMIW_HDMIEDID_A +#undef AUD_HDMIW_INFOFR_A +#undef AUD_PORT_EN_HD_CFG +#undef AUD_OUT_DIG_CNVT_A +#undef AUD_OUT_STR_DESC_A +#undef AUD_OUT_CH_STR +#undef AUD_PINW_CONNLNG_LIST +#undef AUD_CNTL_ST_A +#undef AUD_HDMIW_STATUS +#undef AUD_CONFIG_B +#undef AUD_MISC_CTRL_B +#undef AUD_CTS_ENABLE_B +#undef AUD_HDMIW_HDMIEDID_B +#undef AUD_HDMIW_INFOFR_B +#undef AUD_OUT_DIG_CNVT_B +#undef AUD_OUT_STR_DESC_B +#undef AUD_CNTL_ST_B +#undef AUD_CONFIG_C +#undef AUD_MISC_CTRL_C +#undef AUD_CTS_ENABLE_C +#undef AUD_HDMIW_HDMIEDID_C +#undef AUD_HDMIW_INFOFR_C +#undef AUD_OUT_DIG_CNVT_C +#undef AUD_OUT_STR_DESC_C + +#undef VIDEO_DIP_CTL_A +#undef VIDEO_DIP_CTL_B +#undef VIDEO_DIP_CTL_C +#undef VIDEO_DIP_CTL_D +#undef VIDEO_DIP_DATA + +/* + * Haswell registers + */ + +/* DisplayPort Transport Control */ +#define DP_TP_CTL_A 0x64040 +#define DP_TP_CTL_B 0x64140 +#define DP_TP_CTL_C 0x64240 +#define DP_TP_CTL_D 0x64340 +#define DP_TP_CTL_E 0x64440 + +/* DisplayPort Transport Status */ +#define DP_TP_ST_A 0x64044 +#define DP_TP_ST_B 0x64144 +#define DP_TP_ST_C 0x64244 +#define DP_TP_ST_D 0x64344 +#define DP_TP_ST_E 0x64444 + +/* Transcoder configuration */ +#define TRANS_CONF_A 0xF0008 +#define TRANS_CONF_B 0xF1008 +#define TRANS_CONF_C 0xF2008 + +/* DDI Buffer Control */ +#define DDI_BUF_CTL_A 0x64000 +#define DDI_BUF_CTL_B 0x64100 +#define DDI_BUF_CTL_C 0x64200 +#define DDI_BUF_CTL_D 0x64300 +#define DDI_BUF_CTL_E 0x64400 + +/* DDI Buffer Translation */ +#define DDI_BUF_TRANS_A 0x64e00 +#define DDI_BUF_TRANS_B 0x64e60 +#define DDI_BUF_TRANS_C 0x64ec0 +#define DDI_BUF_TRANS_D 0x64f20 +#define DDI_BUF_TRANS_E 0x64f80 + +/* DDI Aux Channel */ +#define DDI_AUX_CHANNEL_CTRL 0x64010 +#define DDI_AUX_DATA 0x64014 +#define DDI_AUX_TST 0x64028 + +/* DDI CRC Control */ +#define DDI_CRC_CTL_A 0x64050 +#define DDI_CRC_CTL_B 0x64150 +#define DDI_CRC_CTL_C 0x64250 +#define DDI_CRC_CTL_D 0x64350 +#define DDI_CRC_CTL_E 0x64450 + +/* Pipe DDI Function Control */ +#define PIPE_DDI_FUNC_CTL_A 0x60400 +#define PIPE_DDI_FUNC_CTL_B 0x61400 +#define PIPE_DDI_FUNC_CTL_C 0x62400 +#define PIPE_DDI_FUNC_CTL_EDP 0x6F400 + +/* Pipe Configuration */ +#define PIPE_CONF_A 0x70008 +#define PIPE_CONF_B 0x71008 +#define PIPE_CONF_C 0x72008 +#define PIPE_CONF_EDP 0x7F008 + +/* Audio registers */ +#define AUD_CONFIG_A 0x65000 +#define AUD_MISC_CTRL_A 0x65010 +#define AUD_VID_DID 0x65020 +#define AUD_RID 0x65024 +#define AUD_CTS_ENABLE_A 0x65028 +#define AUD_PWRST 0x6504C +#define AUD_HDMIW_HDMIEDID_A 0x65050 +#define AUD_HDMIW_INFOFR_A 0x65054 +#define AUD_PORT_EN_HD_CFG 0x6507C +#define AUD_OUT_DIG_CNVT_A 0x65080 +#define AUD_OUT_STR_DESC_A 0x65084 +#define AUD_OUT_CHAN_MAP 0x65088 +#define AUD_PINW_CONNLNG_LIST_A 0x650A8 +#define AUD_PINW_CONNLNG_LIST_B 0x651A8 +#define AUD_PINW_CONNLNG_LIST_C 0x652A8 +#define AUD_PIPE_CONN_SEL_CTRL 0x650AC +#define AUD_PIN_ELD_CP_VLD 0x650C0 +#define AUD_HDMIW_STATUS 0x650D4 +#define AUD_CONFIG_B 0x65100 +#define AUD_MISC_CTRL_B 0x65110 +#define AUD_CTS_ENABLE_B 0x65128 +#define AUD_HDMIW_HDMIEDID_B 0x65150 +#define AUD_HDMIW_INFOFR_B 0x65154 +#define AUD_OUT_DIG_CNVT_B 0x65180 +#define AUD_OUT_STR_DESC_B 0x65184 +#define AUD_CONFIG_C 0x65200 +#define AUD_MISC_CTRL_C 0x65210 +#define AUD_CTS_ENABLE_C 0x65228 +#define AUD_HDMIW_HDMIEDID_C 0x65250 +#define AUD_HDMIW_INFOFR_C 0x65254 +#define AUD_OUT_DIG_CNVT_C 0x65280 +#define AUD_OUT_STR_DESC_C 0x65284 +#define AUD_DIP_ELD_CTRL_ST_A 0x650b4 +#define AUD_DIP_ELD_CTRL_ST_B 0x651b4 +#define AUD_DIP_ELD_CTRL_ST_C 0x652b4 + +/* Video DIP Control */ +#define VIDEO_DIP_CTL_A 0x60200 +#define VIDEO_DIP_CTL_B 0x61200 +#define VIDEO_DIP_CTL_C 0x62200 +#define VIDEO_DIP_CTL_D 0x63200 + +#define VIDEO_DIP_DATA 0x60220 +#define VIDEO_DIP_ECC 0x60240 + +#define AUD_DP_DIP_STATUS 0x65f20 + + +static void dump_hsw(void) +{ + uint32_t dword; + int i; + + /* HSW DDI Buffer */ + dump_reg(DDI_BUF_CTL_A, "DDI Buffer Controler A"); + dump_reg(DDI_BUF_CTL_B, "DDI Buffer Controler B"); + dump_reg(DDI_BUF_CTL_C, "DDI Buffer Controler C"); + dump_reg(DDI_BUF_CTL_D, "DDI Buffer Controler D"); + dump_reg(DDI_BUF_CTL_E, "DDI Buffer Controler E"); + + /* HSW Pipe Function */ + dump_reg(PIPE_CONF_A, "PIPE Configuration A"); + dump_reg(PIPE_CONF_B, "PIPE Configuration B"); + dump_reg(PIPE_CONF_C, "PIPE Configuration C"); + dump_reg(PIPE_CONF_EDP, "PIPE Configuration EDP"); + + dump_reg(PIPE_DDI_FUNC_CTL_A, "PIPE DDI Function Control A"); + dump_reg(PIPE_DDI_FUNC_CTL_B, "PIPE DDI Function Control B"); + dump_reg(PIPE_DDI_FUNC_CTL_C, "PIPE DDI Function Control C"); + dump_reg(PIPE_DDI_FUNC_CTL_EDP, "PIPE DDI Function Control EDP"); + + /* HSW Display port */ + dump_reg(DP_TP_CTL_A, "DisplayPort Transport A Control"); + dump_reg(DP_TP_CTL_B, "DisplayPort Transport B Control"); + dump_reg(DP_TP_CTL_C, "DisplayPort Transport C Control"); + dump_reg(DP_TP_CTL_D, "DisplayPort Transport D Control"); + dump_reg(DP_TP_CTL_E, "DisplayPort Transport E Control"); + + dump_reg(DP_TP_ST_A, "DisplayPort Transport A Status"); + dump_reg(DP_TP_ST_B, "DisplayPort Transport B Status"); + dump_reg(DP_TP_ST_C, "DisplayPort Transport C Status"); + dump_reg(DP_TP_ST_D, "DisplayPort Transport D Status"); + dump_reg(DP_TP_ST_E, "DisplayPort Transport E Status"); + + /* HSW Transcoder A configuration */ + dump_reg(TRANS_CONF_A, "Transcoder A Configuration"); + dump_reg(TRANS_CONF_B, "Transcoder B Configuration"); + dump_reg(TRANS_CONF_C, "Transcoder C Configuration"); + + /* HSW North Display Audio */ + dump_reg(AUD_CONFIG_A, "Audio Configuration - Transcoder A"); + dump_reg(AUD_CONFIG_B, "Audio Configuration - Transcoder B"); + dump_reg(AUD_CONFIG_C, "Audio Configuration - Transcoder C"); + dump_reg(AUD_MISC_CTRL_A, "Audio MISC Control for Transcoder A"); + dump_reg(AUD_MISC_CTRL_B, "Audio MISC Control for Transcoder B"); + dump_reg(AUD_MISC_CTRL_C, "Audio MISC Control for Transcoder C"); + dump_reg(AUD_VID_DID, "Audio Vendor ID / Device ID"); + dump_reg(AUD_RID, "Audio Revision ID"); + dump_reg(AUD_CTS_ENABLE_A, "Audio CTS Programming Enable - Transcoder A"); + dump_reg(AUD_CTS_ENABLE_B, "Audio CTS Programming Enable - Transcoder B"); + dump_reg(AUD_CTS_ENABLE_C, "Audio CTS Programming Enable - Transcoder C"); + dump_reg(AUD_PWRST, "Audio Power State (Function Group, Convertor, Pin Widget)"); + dump_reg(AUD_HDMIW_HDMIEDID_A, "HDMI Data EDID Block - Transcoder A"); + dump_reg(AUD_HDMIW_HDMIEDID_B, "HDMI Data EDID Block - Transcoder B"); + dump_reg(AUD_HDMIW_HDMIEDID_C, "HDMI Data EDID Block - Transcoder C"); + dump_reg(AUD_HDMIW_INFOFR_A, "Audio Widget Data Island Packet - Transcoder A"); + dump_reg(AUD_HDMIW_INFOFR_B, "Audio Widget Data Island Packet - Transcoder B"); + dump_reg(AUD_HDMIW_INFOFR_C, "Audio Widget Data Island Packet - Transcoder C"); + + dump_reg(AUD_PORT_EN_HD_CFG, "Audio Pipe and Convert Configs"); + dump_reg(AUD_OUT_DIG_CNVT_A, "Audio Digital Converter - Conv A"); + dump_reg(AUD_OUT_DIG_CNVT_B, "Audio Digital Converter - Conv B"); + dump_reg(AUD_OUT_DIG_CNVT_C, "Audio Digital Converter - Conv C"); + dump_reg(AUD_OUT_CHAN_MAP, "Audio Output Channel Mapping"); + dump_reg(AUD_OUT_STR_DESC_A, "Audio Stream Descriptor Format - Conv A"); + dump_reg(AUD_OUT_STR_DESC_B, "Audio Stream Descriptor Format - Conv B"); + dump_reg(AUD_OUT_STR_DESC_C, "Audio Stream Descriptor Format - Conv C"); + dump_reg(AUD_PINW_CONNLNG_LIST_A, "Audio Connection List entry and Length - Transcoder A"); + dump_reg(AUD_PINW_CONNLNG_LIST_B, "Audio Connection List entry and Length - Transcoder B"); + dump_reg(AUD_PINW_CONNLNG_LIST_C, "Audio Connection List entry and Length - Transcoder C"); + dump_reg(AUD_PIPE_CONN_SEL_CTRL, "Audio Pipe Connection Select Control"); + dump_reg(AUD_DIP_ELD_CTRL_ST_A, "Audio DIP and ELD control state - Transcoder A"); + dump_reg(AUD_DIP_ELD_CTRL_ST_B, "Audio DIP and ELD control state - Transcoder B"); + dump_reg(AUD_DIP_ELD_CTRL_ST_C, "Audio DIP and ELD control state - Transcoder C"); + dump_reg(AUD_PIN_ELD_CP_VLD, "audio pin eld valid status"); + dump_reg(AUD_HDMIW_STATUS, "Audio HDMI FIFO Status"); + + printf("\nDetails:\n\n"); + + dword = INREG(AUD_VID_DID); + printf("AUD_VID_DID vendor id\t\t\t\t\t0x%x\n", dword >> 16); + printf("AUD_VID_DID device id\t\t\t\t\t0x%x\n", dword & 0xffff); + + dword = INREG(AUD_RID); + printf("AUD_RID Major_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_RID Minor_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_RID Revision_Id\t\t\t\t\t0x%lx\n", BITS(dword, 15, 8)); + printf("AUD_RID Stepping_Id\t\t\t\t\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(AUD_DIP_ELD_CTRL_ST_A); + printf("Audio DIP and ELD control state for TranscoderA\n"); + printf("Audio DIP port select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + + printf("Audio DIP type enable status\t\t\t\t[0x%lx] %s\n", + BITS(dword, 24, 21), dip_type[BIT(dword, 21)]); + + printf("DIP Buffer Index \t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 18), dip_index[BITS(dword, 20, 18)]); + printf("DIP_transmission_frequency\t\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("ELD_ACK\t\t\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("ELD_buffer_size\t\t\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(AUD_DIP_ELD_CTRL_ST_B); + printf("Audio DIP and ELD control state for TranscoderB\n"); + printf("Audio DIP port select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + + printf("Audio DIP type enable status\t\t\t\t[0x%lx] %s\n", + BITS(dword, 24, 21), dip_type[BIT(dword, 21)]); + + printf("DIP Buffer Index \t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 18), dip_index[BITS(dword, 20, 18)]); + printf("DIP_transmission_frequency\t\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("ELD_ACK\t\t\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("ELD_buffer_size\t\t\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(AUD_DIP_ELD_CTRL_ST_C); + printf("Audio DIP and ELD control state for TranscoderC\n"); + printf("Audio DIP port select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + + printf("Audio DIP type enable status\t\t\t\t[0x%lx] %s\n", + BITS(dword, 24, 21), dip_type[BIT(dword, 21)]); + + printf("DIP Buffer Index \t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 18), dip_index[BITS(dword, 20, 18)]); + printf("DIP_transmission_frequency\t\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("ELD_ACK\t\t\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("ELD_buffer_size\t\t\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(DDI_BUF_CTL_A); + printf("DDI A Buffer control\n"); + printf("DDI Buffer Enable\t\t\t\t\t%ld\n", BIT(dword, 31)); + printf("DP port width\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 3, 1), dp_port_width[BITS(dword, 3, 1)]); + dword = INREG(DDI_BUF_CTL_B); + printf("DDI B Buffer control\n"); + printf("DDI Buffer Enable\t\t\t\t\t%ld\n", BIT(dword, 31)); + printf("DP port width\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 3, 1), dp_port_width[BITS(dword, 3, 1)]); + dword = INREG(DDI_BUF_CTL_C); + printf("DDI C Buffer control\n"); + printf("DDI Buffer Enable\t\t\t\t\t%ld\n", BIT(dword, 31)); + printf("DP port width\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 3, 1), dp_port_width[BITS(dword, 3, 1)]); + dword = INREG(DDI_BUF_CTL_D); + printf("DDI D Buffer control\n"); + printf("DDI Buffer Enable\t\t\t\t\t%ld\n", BIT(dword, 31)); + printf("DP port width\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 3, 1), dp_port_width[BITS(dword, 3, 1)]); + dword = INREG(DDI_BUF_CTL_E); + printf("DDI E Buffer control\n"); + printf("DDI Buffer Enable\t\t\t\t\t%ld\n", BIT(dword, 31)); + printf("DP port width\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 3, 1), dp_port_width[BITS(dword, 3, 1)]); + + dword = INREG(PIPE_DDI_FUNC_CTL_A); + printf("Pipe A DDI Function Control\n"); + printf("PIPE DDI Function Enable\t\t\t\t[0x%lx]\n", BIT(dword, 31)); + printf("PIPE DDI selection\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 30, 28), + trans_to_port_sel[BITS(dword, 30, 28)]); + printf("PIPE DDI Mode\t\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 26, 24), ddi_mode[BITS(dword, 26, 24)]); + printf("BITS per color\t\t\t\t\t\t[0x%lx]\n", BITS(dword, 22, 20)); + + dword = INREG(PIPE_DDI_FUNC_CTL_B); + printf("Pipe B DDI Function Control\n"); + printf("PIPE DDI Function Enable\t\t\t\t[0x%lx]\n", BIT(dword, 31)); + printf("PIPE DDI selection\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 30, 28), + trans_to_port_sel[BITS(dword, 30, 28)]); + printf("PIPE DDI Mode \t\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 26, 24), ddi_mode[BITS(dword, 26, 24)]); + printf("BITS per color\t\t\t\t\t\t[0x%lx]\n", BITS(dword, 22, 20)); + + dword = INREG(PIPE_DDI_FUNC_CTL_C); + printf("Pipe C DDI Function Control\n"); + printf("PIPE DDI Function Enable\t\t\t\t[0x%lx]\n", BIT(dword, 31)); + printf("PIPE DDI selection\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 30, 28), + trans_to_port_sel[BITS(dword, 30, 28)]); + printf("PIPE DDI Mode \t\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 26, 24), ddi_mode[BITS(dword, 26, 24)]); + printf("BITS per color\t\t\t\t\t\t[0x%lx]\n", BITS(dword, 22, 20)); + + dword = INREG(AUD_CONFIG_A); + printf("AUD_CONFIG_A N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_A N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_A Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_A Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_A Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_A Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + dword = INREG(AUD_CONFIG_B); + printf("AUD_CONFIG_B N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_B N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_B Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_B Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_B Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_B Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + dword = INREG(AUD_CONFIG_C); + printf("AUD_CONFIG_C N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_C N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_C Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_C Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_C Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_C Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + + dword = INREG(AUD_CTS_ENABLE_A); + printf("AUD_CTS_ENABLE_A Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_A CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_A CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + dword = INREG(AUD_CTS_ENABLE_B); + printf("AUD_CTS_ENABLE_B Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_B CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_B CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + dword = INREG(AUD_CTS_ENABLE_C); + printf("AUD_CTS_ENABLE_C Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_C CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_C CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + + dword = INREG(AUD_MISC_CTRL_A); + printf("AUD_MISC_CTRL_A Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_A Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_A Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_A Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + dword = INREG(AUD_MISC_CTRL_B); + printf("AUD_MISC_CTRL_B Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_B Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_B Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_B Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + dword = INREG(AUD_MISC_CTRL_C); + printf("AUD_MISC_CTRL_C Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_C Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_C Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_C Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + + dword = INREG(AUD_PWRST); + printf("AUD_PWRST Func_Grp_Dev_PwrSt_Curr \t%s\n", power_state[BITS(dword, 27, 26)]); + printf("AUD_PWRST Func_Grp_Dev_PwrSt_Set \t%s\n", power_state[BITS(dword, 25, 24)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 15, 14)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Requsted \t%s\n", power_state[BITS(dword, 13, 12)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 19, 18)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Requested \t%s\n", power_state[BITS(dword, 17, 16)]); + printf("AUD_PWRST ConvC_Widget_PwrSt_Curr \t%s\n", power_state[BITS(dword, 23, 22)]); + printf("AUD_PWRST ConvC_Widget_PwrSt_Req \t%s\n", power_state[BITS(dword, 21, 20)]); + printf("AUD_PWRST PinB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 3, 2)]); + printf("AUD_PWRST PinB_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 1, 0)]); + printf("AUD_PWRST PinC_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 7, 6)]); + printf("AUD_PWRST PinC_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 5, 4)]); + printf("AUD_PWRST PinD_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 11, 10)]); + printf("AUD_PWRST PinD_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 9, 8)]); + + dword = INREG(AUD_PORT_EN_HD_CFG); + printf("AUD_PORT_EN_HD_CFG Convertor_A_Digen\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_PORT_EN_HD_CFG Convertor_B_Digen\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_PORT_EN_HD_CFG Convertor_C_Digen\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_PORT_EN_HD_CFG ConvertorA_Stream_ID\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_PORT_EN_HD_CFG ConvertorB_Stream_ID\t\t%lu\n", BITS(dword, 11, 8)); + printf("AUD_PORT_EN_HD_CFG ConvertorC_Stream_ID\t\t%lu\n", BITS(dword, 15, 12)); + printf("AUD_PORT_EN_HD_CFG Port_B_Out_Enable\t\t\t%lu\n", BIT(dword, 16)); + printf("AUD_PORT_EN_HD_CFG Port_C_Out_Enable\t\t\t%lu\n", BIT(dword, 17)); + printf("AUD_PORT_EN_HD_CFG Port_D_Out_Enable\t\t\t%lu\n", BIT(dword, 18)); + printf("AUD_PORT_EN_HD_CFG Port_B_Amp_Mute_Status\t\t%lu\n", BIT(dword, 20)); + printf("AUD_PORT_EN_HD_CFG Port_C_Amp_Mute_Status\t\t%lu\n", BIT(dword, 21)); + printf("AUD_PORT_EN_HD_CFG Port_D_Amp_Mute_Status\t\t%lu\n", BIT(dword, 22)); + + dword = INREG(AUD_OUT_DIG_CNVT_A); + printf("AUD_OUT_DIG_CNVT_A V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_A VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_A PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_A Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_A NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_A PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_A Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_A Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_A Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_A Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + dword = INREG(AUD_OUT_DIG_CNVT_B); + printf("AUD_OUT_DIG_CNVT_B V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_B VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_B PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_B Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_B NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_B PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_B Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_B Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_B Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_B Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + dword = INREG(AUD_OUT_DIG_CNVT_C); + printf("AUD_OUT_DIG_CNVT_C V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_C VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_C PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_C Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_C NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_C PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_C Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_C Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_C Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_C Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + printf("AUD_OUT_CHAN_MAP Converter_Channel_MAP PORTB PORTC PORTD\n"); + for (i = 0; i < 8; i++) { + OUTREG(AUD_OUT_CHAN_MAP, i | (i << 8) | (i << 16)); + dword = INREG(AUD_OUT_CHAN_MAP); + printf("\t\t\t\t%lu\t%lu\t%lu\t%lu\n", + 1 + BITS(dword, 3, 0), + 1 + BITS(dword, 7, 4), + 1 + BITS(dword, 15, 12), + 1 + BITS(dword, 23, 20)); + } + + dword = INREG(AUD_OUT_STR_DESC_A); + printf("AUD_OUT_STR_DESC_A Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_A Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_A Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC_B); + printf("AUD_OUT_STR_DESC_B Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_B Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_B Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC_C); + printf("AUD_OUT_STR_DESC_C Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_C Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_C Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_PINW_CONNLNG_SEL); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_B\t%#lx\n", BITS(dword, 7, 0)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_C\t%#lx\n", BITS(dword, 15, 8)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_D\t%#lx\n", BITS(dword, 23, 16)); + + dword = INREG(AUD_PIN_ELD_CP_VLD); + printf("AUD_CNTRL_ST2 CP_ReadyB\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_CNTRL_ST2 ELD_validB\t\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_CNTRL_ST2 OUT_enableB\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_CNTRL_ST2 CP_ReadyC\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_CNTRL_ST2 ELD_validC\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTRL_ST2 OUT_enableC\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_CNTRL_ST2 CP_ReadyD\t\t\t\t%lu\n", BIT(dword, 9)); + printf("AUD_CNTRL_ST2 ELD_validD\t\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_CNTRL_ST2 OUT_enableD\t\t\t\t%lu\n", BIT(dword, 10)); + + dword = INREG(AUD_HDMIW_STATUS); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 27)); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 26)); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 29)); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 28)); + printf("AUD_HDMIW_STATUS Conv_C_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 31)); + printf("AUD_HDMIW_STATUS Conv_C_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 30)); + printf("AUD_HDMIW_STATUS BCLK/CDCLK_FIFO_Overrun\t\t%lu\n", BIT(dword, 25)); + printf("AUD_HDMIW_STATUS Function_Reset\t\t\t%lu\n", BIT(dword, 24)); + + printf("AUD_HDMIW_HDMIEDID_A HDMI ELD:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_A); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_DIP_ELD_CTRL_ST_A, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_A))); + printf("\n"); + + printf("AUD_HDMIW_HDMIEDID_B HDMI ELD:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_B); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_DIP_ELD_CTRL_ST_B, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_B))); + printf("\n"); + + printf("AUD_HDMIW_HDMIEDID_C HDMI ELD:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_C); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_DIP_ELD_CTRL_ST_C, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_C))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_A HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_A); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_DIP_ELD_CTRL_ST_A, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_A))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_B HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_B); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_DIP_ELD_CTRL_ST_B, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_B))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_C HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_C); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_DIP_ELD_CTRL_ST_C, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_C))); + printf("\n"); +} + +int main(int argc, char **argv) +{ + struct pci_device *pci_dev; + + pci_dev = intel_get_pci_device(); + devid = pci_dev->device_id; /* XXX not true when mapping! */ + + do_self_tests(); + + if (argc == 2) + intel_map_file(argv[1]); + else + intel_get_mmio(pci_dev); + + if (IS_GEN6(devid) || IS_GEN7(devid) || getenv("HAS_PCH_SPLIT")) { + if (IS_HASWELL(devid)) { + printf("Haswell audio registers:\n\n"); + dump_hsw(); + return 0; + } + printf("%s audio registers:\n\n", + IS_GEN6(devid) ? "SandyBridge" : "IvyBridge"); + intel_check_pch(); + dump_cpt(); + } else if (IS_GEN5(devid)) { + printf("Ironlake audio registers:\n\n"); + dump_ironlake(); + } else if (IS_G4X(devid)) { + printf("G45 audio registers:\n\n"); + dump_eaglelake(); + } + + return 0; +} diff --git a/tools/intel_backlight.c b/tools/intel_backlight.c new file mode 100644 index 00000000..bd7c813b --- /dev/null +++ b/tools/intel_backlight.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "intel_gpu_tools.h" + +/* XXX PCH only today */ + +static uint32_t reg_read(uint32_t reg) +{ + return *(volatile uint32_t *)((volatile char*)mmio + reg); +} + +static void reg_write(uint32_t reg, uint32_t val) +{ + *(volatile uint32_t *)((volatile char*)mmio + reg) = val; +} + +int main(int argc, char** argv) +{ + uint32_t current, max; + + intel_get_mmio(intel_get_pci_device()); + + current = reg_read(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; + max = reg_read(BLC_PWM_PCH_CTL2) >> 16; + + printf ("current backlight value: %d%%\n", current * 100 / max); + + if (argc > 1) { + uint32_t v = atoi (argv[1]) * max / 100; + if (v > max) + v = max; + reg_write(BLC_PWM_CPU_CTL, + (reg_read(BLC_PWM_CPU_CTL) &~ BACKLIGHT_DUTY_CYCLE_MASK) | v); + (void) reg_read(BLC_PWM_CPU_CTL); + printf ("set backlight to %d%%\n", v * 100 / max); + } + + return 0; +} diff --git a/tools/intel_bios.h b/tools/intel_bios.h new file mode 100644 index 00000000..12850203 --- /dev/null +++ b/tools/intel_bios.h @@ -0,0 +1,731 @@ +/* + * Copyright 2006 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifndef _INTEL_BIOS_H_ +#define _INTEL_BIOS_H_ + +#include <stdint.h> + +struct vbt_header { + char signature[20]; /**< Always starts with 'VBT$' */ + uint16_t version; /**< decimal */ + uint16_t header_size; /**< in bytes */ + uint16_t vbt_size; /**< in bytes */ + uint8_t vbt_checksum; + uint8_t reserved0; + uint32_t bdb_offset; /**< from beginning of VBT */ + uint32_t aim_offset[4]; /**< from beginning of VBT */ +} __attribute__ ((packed)); + +struct bdb_header { + char signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ + uint16_t version; /**< decimal */ + uint16_t header_size; /**< in bytes */ + uint16_t bdb_size; /**< in bytes */ +} __attribute__ ((packed)); + +/* + * There are several types of BIOS data blocks (BDBs), each block has + * an ID and size in the first 3 bytes (ID in first, size in next 2). + * Known types are listed below. + */ +#define BDB_GENERAL_FEATURES 1 +#define BDB_GENERAL_DEFINITIONS 2 +#define BDB_OLD_TOGGLE_LIST 3 +#define BDB_MODE_SUPPORT_LIST 4 +#define BDB_GENERIC_MODE_TABLE 5 +#define BDB_EXT_MMIO_REGS 6 +#define BDB_SWF_IO 7 +#define BDB_SWF_MMIO 8 +#define BDB_DOT_CLOCK_TABLE 9 +#define BDB_MODE_REMOVAL_TABLE 10 +#define BDB_CHILD_DEVICE_TABLE 11 +#define BDB_DRIVER_FEATURES 12 +#define BDB_DRIVER_PERSISTENCE 13 +#define BDB_EXT_TABLE_PTRS 14 +#define BDB_DOT_CLOCK_OVERRIDE 15 +#define BDB_DISPLAY_SELECT 16 +/* 17 rsvd */ +#define BDB_DRIVER_ROTATION 18 +#define BDB_DISPLAY_REMOVE 19 +#define BDB_OEM_CUSTOM 20 +#define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */ +#define BDB_SDVO_LVDS_OPTIONS 22 +#define BDB_SDVO_PANEL_DTDS 23 +#define BDB_SDVO_LVDS_PNP_IDS 24 +#define BDB_SDVO_LVDS_POWER_SEQ 25 +#define BDB_TV_OPTIONS 26 +#define BDB_EDP 27 +#define BDB_LVDS_OPTIONS 40 +#define BDB_LVDS_LFP_DATA_PTRS 41 +#define BDB_LVDS_LFP_DATA 42 +#define BDB_LVDS_BACKLIGHT 43 +#define BDB_LVDS_POWER 44 +#define BDB_SKIP 254 /* VBIOS private block, ignore */ + +struct bdb_general_features { + /* bits 1 */ + unsigned char panel_fitting:2; + unsigned char flexaim:1; + unsigned char msg_enable:1; + unsigned char clear_screen:3; + unsigned char color_flip:1; + + /* bits 2 */ + unsigned char download_ext_vbt:1; + unsigned char enable_ssc:1; + unsigned char ssc_freq:1; + unsigned char enable_lfp_on_override:1; + unsigned char disable_ssc_ddt:1; + unsigned char rsvd8:3; /* finish byte */ + + /* bits 3 */ + unsigned char disable_smooth_vision:1; + unsigned char single_dvi:1; + unsigned char rsvd9:6; /* finish byte */ + + /* bits 4 */ + unsigned char legacy_monitor_detect; + + /* bits 5 */ + unsigned char int_crt_support:1; + unsigned char int_tv_support:1; + unsigned char rsvd11:6; /* finish byte */ +} __attribute__ ((packed)); + +#define GPIO_PIN_NONE 0x00 /* "N/A" */ +#define GPIO_PIN_I2C 0x01 /* "I2C GPIO pins" */ +#define GPIO_PIN_CRT_DDC 0x02 /* "Analog CRT DDC GPIO pins" */ +/* 915+ */ +#define GPIO_PIN_LVDS 0x03 /* "Integrated LVDS DDC GPIO pins" */ +#define GPIO_PIN_SDVO_I2C 0x05 /* "sDVO I2C GPIO pins" */ +#define GPIO_PIN_SDVO_DDC1 0x1D /* "SDVO DDC1 GPIO pins" */ +#define GPIO_PIN_SDVO_DDC2 0x2D /* "SDVO DDC2 GPIO pins" */ +/* pre-915 */ +#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ +#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */ +#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */ +#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */ + +/* Pre 915 */ +#define DEVICE_TYPE_NONE 0x00 +#define DEVICE_TYPE_CRT 0x01 +#define DEVICE_TYPE_TV 0x09 +#define DEVICE_TYPE_EFP 0x12 +#define DEVICE_TYPE_LFP 0x22 +/* On 915+ */ +#define DEVICE_TYPE_CRT_DPMS 0x6001 +#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001 +#define DEVICE_TYPE_TV_COMPOSITE 0x0209 +#define DEVICE_TYPE_TV_MACROVISION 0x0289 +#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c +#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609 +#define DEVICE_TYPE_TV_SCART 0x0209 +#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009 +#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012 +#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052 +#define DEVICE_TYPE_EFP_DVI_I 0x6053 +#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152 +#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2 +#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062 +#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162 +#define DEVICE_TYPE_LFP_PANELLINK 0x5012 +#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042 +#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062 +#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162 +#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2 +#define DEVICE_TYPE_INT_HDMI 0xf0D2 + +#define DEVICE_TYPE_INT_LFP 0x1022 +#define DEVICE_TYPE_INT_TV 0x1009 +#define DEVICE_TYPE_DP 0x68C6 +#define DEVICE_TYPE_DP_HDMI_DVI 0x60d6 +#define DEVICE_TYPE_DP_DVI 0x68d6 +#define DEVICE_TYPE_HDMI_DVI 0x60d2 +#define DEVICE_TYPE_DVI 0x68d2 +#define DEVICE_TYPE_eDP 0x78C6 + +#define DEVICE_CFG_NONE 0x00 +#define DEVICE_CFG_12BIT_DVOB 0x01 +#define DEVICE_CFG_12BIT_DVOC 0x02 +#define DEVICE_CFG_24BIT_DVOBC 0x09 +#define DEVICE_CFG_24BIT_DVOCB 0x0a +#define DEVICE_CFG_DUAL_DVOB 0x11 +#define DEVICE_CFG_DUAL_DVOC 0x12 +#define DEVICE_CFG_DUAL_DVOBC 0x13 +#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19 +#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a + +#define DEVICE_WIRE_NONE 0x00 +#define DEVICE_WIRE_DVOB 0x01 +#define DEVICE_WIRE_DVOC 0x02 +#define DEVICE_WIRE_DVOBC 0x03 +#define DEVICE_WIRE_DVOBB 0x05 +#define DEVICE_WIRE_DVOCC 0x06 +#define DEVICE_WIRE_DVOB_MASTER 0x0d +#define DEVICE_WIRE_DVOC_MASTER 0x0e + +#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */ +#define DEVICE_PORT_DVOB 0x01 +#define DEVICE_PORT_DVOC 0x02 + +#define DEVICE_PORT_NONE 0 +#define DEVICE_PORT_HDMIB 1 +#define DEVICE_PORT_HDMIC 2 +#define DEVICE_PORT_HDMID 3 +#define DEVICE_PORT_DPB 7 +#define DEVICE_PORT_DPC 8 +#define DEVICE_PORT_DPD 9 + +#define DEVICE_INFO_NONE 0 +#define DEVICE_INFO_HDMI_CERT 1 +#define DEVICE_INFO_DP 2 +#define DEVICE_INFO_DVI 3 + +struct child_device_config { + uint16_t handle; + uint16_t device_type; /* See DEVICE_TYPE_* above */ + uint8_t device_id[10]; + uint16_t addin_offset; + uint8_t dvo_port; /* See DEVICE_PORT_* above */ + uint8_t i2c_pin; + uint8_t slave_addr; + uint8_t ddc_pin; + uint16_t edid_ptr; + uint8_t dvo_cfg; /* See DEVICE_CFG_* above */ + uint8_t dvo2_port; + uint8_t i2c2_pin; + uint8_t slave2_addr; + uint8_t ddc2_pin; + uint8_t capabilities; + uint8_t dvo_wiring; /* See DEVICE_WIRE_* above */ + uint8_t dvo2_wiring; + uint16_t extended_type; + uint8_t dvo_function; +} __attribute__ ((packed)); + +struct efp_child_device_config { + uint16_t handle; + uint16_t device_type; + uint8_t skip1[12]; + uint8_t port; + uint8_t skip2[2]; + uint8_t ddc_pin; + uint8_t skip3[3]; + uint8_t docked_port; + uint8_t hdmi_compat:1; + uint8_t conn_info:3; + uint8_t skip4:4; + uint8_t aux_chan; + uint8_t dongle_detect; + uint8_t skip5[6]; +} __attribute__ ((packed)); + +struct bdb_general_definitions { + unsigned char crt_ddc_gmbus_pin; /* see GPIO_PIN_* above */ + + /* DPMS bits */ + unsigned char dpms_acpi:1; + unsigned char skip_boot_crt_detect:1; + unsigned char dpms_aim:1; + unsigned char rsvd1:5; /* finish byte */ + + /* boot device bits */ + unsigned char boot_display[2]; + unsigned char child_dev_size; + + /* + * Device info: + * If TV is present, it'll be at devices[0] + * LVDS will be next, either devices[0] or [1], if present + * Max total will be 6, but could be as few as 4 if both + * TV and LVDS are missing, so be careful when interpreting + * [4] and [5]. + */ + struct child_device_config devices[0]; + /* may be another device block here on some platforms */ +} __attribute__ ((packed)); + +#define DEVICE_CHILD_SIZE 7 + +struct bdb_child_devices { + uint8_t child_structure_size; + struct child_device_config children[DEVICE_CHILD_SIZE]; +} __attribute__ ((packed)); + +struct bdb_lvds_options { + uint8_t panel_type; + uint8_t rsvd1; + /* LVDS capabilities, stored in a dword */ + uint8_t pfit_mode:2; + uint8_t pfit_text_mode_enhanced:1; + uint8_t pfit_gfx_mode_enhanced:1; + uint8_t pfit_ratio_auto:1; + uint8_t pixel_dither:1; + uint8_t lvds_edid:1; + uint8_t rsvd2:1; + uint8_t rsvd4; +} __attribute__ ((packed)); + +/* 915+ only */ +struct bdb_tv_features { + /* need to verify bit ordering */ + uint16_t under_over_scan_via_yprpb:2; + uint16_t rsvd1:10; + uint16_t under_over_scan_via_dvi:2; + uint16_t add_overscan_mode:1; + uint16_t rsvd2:1; +} __attribute__ ((packed)); + +struct lvds_fp_timing { + uint16_t x_res; + uint16_t y_res; + uint32_t lvds_reg; + uint32_t lvds_reg_val; + uint32_t pp_on_reg; + uint32_t pp_on_reg_val; + uint32_t pp_off_reg; + uint32_t pp_off_reg_val; + uint32_t pp_cycle_reg; + uint32_t pp_cycle_reg_val; + uint32_t pfit_reg; + uint32_t pfit_reg_val; + uint16_t terminator; +} __attribute__ ((packed)); + +struct lvds_dvo_timing { + uint16_t dclk; /**< In 10khz */ + uint8_t hactive; + uint8_t hblank; + uint8_t high_h; /**< 7:4 = hactive 11:8, 3:0 = hblank 11:8 */ + uint8_t vactive; + uint8_t vblank; + uint8_t high_v; /**< 7:4 = vactive 11:8, 3:0 = vblank 11:8 */ + uint8_t hsync_off; + uint8_t hsync_pulse_width; + uint8_t vsync_off; + uint8_t high_hsync_off; /**< 7:6 = hsync off 9:8 */ + uint8_t h_image; + uint8_t v_image; + uint8_t max_hv; + uint8_t h_border; + uint8_t v_border; + uint8_t flags; +} __attribute__ ((packed)); +struct lvds_dvo_timing2 { + uint16_t clock; /**< In 10khz */ + uint8_t hactive_lo; + uint8_t hblank_lo; + uint8_t hblank_hi:4; + uint8_t hactive_hi:4; + uint8_t vactive_lo; + uint8_t vblank_lo; + uint8_t vblank_hi:4; + uint8_t vactive_hi:4; + uint8_t hsync_off_lo; + uint8_t hsync_pulse_width; + uint8_t vsync_pulse_width:4; + uint8_t vsync_off:4; + uint8_t rsvd0:6; + uint8_t hsync_off_hi:2; + uint8_t h_image; + uint8_t v_image; + uint8_t max_hv; + uint8_t h_border; + uint8_t v_border; + uint8_t rsvd1:3; + uint8_t digital:2; + uint8_t vsync_positive:1; + uint8_t hsync_positive:1; + uint8_t rsvd2:1; +} __attribute__((packed)); + +struct lvds_pnp_id { + uint16_t mfg_name; + uint16_t product_code; + uint32_t serial; + uint8_t mfg_week; + uint8_t mfg_year; +} __attribute__ ((packed));; + +/* LFP pointer table contains entries to the struct below */ +struct bdb_lvds_lfp_data_ptr { + uint16_t fp_timing_offset; /* offsets are from start of bdb */ + uint8_t fp_table_size; + uint16_t dvo_timing_offset; + uint8_t dvo_table_size; + uint16_t panel_pnp_id_offset; + uint8_t pnp_table_size; +} __attribute__ ((packed)); + +struct bdb_lvds_lfp_data_ptrs { + uint8_t lvds_entries; + struct bdb_lvds_lfp_data_ptr ptr[16]; +} __attribute__ ((packed)); + +struct bdb_lvds_lfp_data_entry { + struct lvds_fp_timing fp_timing; + struct lvds_dvo_timing dvo_timing; + struct lvds_pnp_id pnp_id; +} __attribute__ ((packed)); + +struct bdb_lvds_lfp_data { + struct bdb_lvds_lfp_data_entry data[16]; +} __attribute__ ((packed)); + +#define BACKLIGHT_TYPE_NONE 0 +#define BACKLIGHT_TYPE_I2C 1 +#define BACKLIGHT_TYPE_PWM 2 + +#define BACKLIGHT_GMBUS_100KHZ 0 +#define BACKLIGHT_GMBUS_50KHZ 1 +#define BACKLIGHT_GMBUS_400KHZ 2 +#define BACKLIGHT_GMBUS_1MHZ 3 + +struct backlight_info { + uint8_t inverter_type:2; /* see BACKLIGHT_TYPE_* above */ + uint8_t inverter_polarity:1; /* 1 means 0 is max, 255 is min */ + uint8_t gpio_pins:3; /* see GPIO_PIN_* above */ + uint8_t gmbus_speed:2; + uint16_t pwm_frequency; /* in Hz */ + uint8_t min_brightness; + /* Next two are only for 915+ systems */ + uint8_t i2c_addr; + uint8_t i2c_cmd; +} __attribute((packed)); + +struct bdb_backlight_control { + uint8_t row_size; + struct backlight_info lfps[16]; +} __attribute__ ((packed)); + +struct bdb_bia { + uint8_t bia_enable:1; + uint8_t bia_level:3; + uint8_t rsvd1:3; + uint8_t als_enable:1; + uint8_t als_response_data[20]; +} __attribute((packed)); + +struct aimdb_header { + char signature[16]; + char oem_device[20]; + uint16_t aimdb_version; + uint16_t aimdb_header_size; + uint16_t aimdb_size; +} __attribute__ ((packed)); + +struct aimdb_block { + uint8_t aimdb_id; + uint16_t aimdb_size; +} __attribute__ ((packed)); + +struct vch_panel_data { + uint16_t fp_timing_offset; + uint8_t fp_timing_size; + uint16_t dvo_timing_offset; + uint8_t dvo_timing_size; + uint16_t text_fitting_offset; + uint8_t text_fitting_size; + uint16_t graphics_fitting_offset; + uint8_t graphics_fitting_size; +} __attribute__ ((packed)); + +struct vch_bdb_22 { + struct aimdb_block aimdb_block; + struct vch_panel_data panels[16]; +} __attribute__ ((packed)); + +#define BLC_INVERTER_TYPE_NONE 0 +#define BLC_INVERTER_TYPE_I2C 1 +#define BLC_INVERTER_TYPE_PWM 2 + +#define BLC_GPIO_NONE 0 +#define BLC_GPIO_I2C 1 +#define BLC_GPIO_CRT_DDC 2 +#define BLC_GPIO_DVI_DDC 3 +#define BLC_GPIO_SDVO_I2C 5 + +struct blc_struct { + uint8_t inverter_type:2; + uint8_t inverter_polarity:1; /* 1 means inverted (0 = max brightness) */ + uint8_t gpio_pins:3; + uint8_t gmbus_speed:2; + uint16_t pwm_freq; /* in Hz */ + uint8_t min_brightness; /* (0-255) */ + uint8_t i2c_slave_addr; + uint8_t i2c_cmd; +} __attribute__ ((packed)); + +struct bdb_lvds_backlight { + uint8_t blcstruct_size; + struct blc_struct panels[16]; +} __attribute__ ((packed)); + +struct bdb_lvds_power { + uint8_t dpst_enabled:1; + uint8_t pwr_prefs:3; + uint8_t rsvd1:3; + uint8_t als_enabled:1; + uint16_t als_backlight1; + uint16_t als_backlight2; + uint16_t als_backlight3; + uint16_t als_backlight4; + uint16_t als_backlight5; +} __attribute__ ((packed)); + +#define BDB_DRIVER_NO_LVDS 0 +#define BDB_DRIVER_INT_LVDS 1 +#define BDB_DRIVER_SDVO_LVDS 2 +#define BDB_DRIVER_EDP 3 + +struct bdb_driver_feature { + uint8_t boot_dev_algorithm:1; + uint8_t block_display_switch:1; + uint8_t allow_display_switch:1; + uint8_t hotplug_dvo:1; + uint8_t dual_view_zoom:1; + uint8_t int15h_hook:1; + uint8_t sprite_in_clone:1; + uint8_t primary_lfp_id:1; + + uint16_t boot_mode_x; + uint16_t boot_mode_y; + uint8_t boot_mode_bpp; + uint8_t boot_mode_refresh; + + uint16_t enable_lfp_primary:1; + uint16_t selective_mode_pruning:1; + uint16_t dual_frequency:1; + uint16_t render_clock_freq:1; /* 0: high freq; 1: low freq */ + uint16_t nt_clone_support:1; + uint16_t power_scheme_ui:1; /* 0: CUI; 1: 3rd party */ + uint16_t sprite_display_assign:1; /* 0: secondary; 1: primary */ + uint16_t cui_aspect_scaling:1; + uint16_t preserve_aspect_ratio:1; + uint16_t sdvo_device_power_down:1; + uint16_t crt_hotplug:1; + uint16_t lvds_config:2; + uint16_t reserved:3; + + uint8_t static_display:1; + uint8_t reserved2:7; + uint16_t legacy_crt_max_x; + uint16_t legacy_crt_max_y; + uint8_t legacy_crt_max_refresh; +} __attribute__ ((packed)); + +struct bdb_sdvo_lvds_options { + uint8_t panel_backlight; + uint8_t h40_set_panel_type; + uint8_t panel_type; + uint8_t ssc_clk_freq; + uint16_t als_low_trip; + uint16_t als_high_trip; + uint8_t sclalarcoeff_tab_row_num; + uint8_t sclalarcoeff_tab_row_size; + uint8_t coefficient[8]; + uint8_t panel_misc_bits_1; + uint8_t panel_misc_bits_2; + uint8_t panel_misc_bits_3; + uint8_t panel_misc_bits_4; +} __attribute__ ((packed)); + +#define EDP_18BPP 0 +#define EDP_24BPP 1 +#define EDP_30BPP 2 +#define EDP_RATE_1_62 0 +#define EDP_RATE_2_7 1 +#define EDP_LANE_1 0 +#define EDP_LANE_2 1 +#define EDP_LANE_4 3 +#define EDP_PREEMPHASIS_NONE 0 +#define EDP_PREEMPHASIS_3_5dB 1 +#define EDP_PREEMPHASIS_6dB 2 +#define EDP_PREEMPHASIS_9_5dB 3 +#define EDP_VSWING_0_4V 0 +#define EDP_VSWING_0_6V 1 +#define EDP_VSWING_0_8V 2 +#define EDP_VSWING_1_2V 3 + +struct edp_power_seq { + uint16_t t3; + uint16_t t7; + uint16_t t9; + uint16_t t10; + uint16_t t12; +} __attribute__ ((packed)); + +struct edp_link_params { + uint8_t rate:4; + uint8_t lanes:4; + uint8_t preemphasis:4; + uint8_t vswing:4; +} __attribute__ ((packed)); + +struct bdb_edp { + struct edp_power_seq power_seqs[16]; + uint32_t color_depth; + uint32_t sdrrs_msa_timing_delay; + struct edp_link_params link_params[16]; +} __attribute__ ((packed)); + +/* + * Driver<->VBIOS interaction occurs through scratch bits in + * GR18 & SWF*. + * + * The VBIOS/firmware will signal to the gfx driver through the ASLE interrupt + * (visible in the interupt regs at bit 0) when it wants something done. + * + * Pre-965: + * The gfx driver can make calls to the VBIOS/firmware through an SMI request, + * generated by writing to offset 0xe0 of the device's config space (see the + * publically available 915 PRM for details). + * + * 965 and above: + * IGD OpRegion requests to the VBIOS/firmware are made using SWSCI, which can + * be triggered by writing to offset 0xe4 (see the publically available + * 965 graphics PRM for details). + */ + +/* GR18 bits are set on display switch and hotkey events */ +#define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */ +#define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */ +#define GR18_HK_NONE (0x0<<3) +#define GR18_HK_LFP_STRETCH (0x1<<3) +#define GR18_HK_TOGGLE_DISP (0x2<<3) +#define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */ +#define GR18_HK_POPUP_DISABLED (0x6<<3) +#define GR18_HK_POPUP_ENABLED (0x7<<3) +#define GR18_HK_PFIT (0x8<<3) +#define GR18_HK_APM_CHANGE (0xa<<3) +#define GR18_HK_MULTIPLE (0xc<<3) +#define GR18_USER_INT_EN (1<<2) +#define GR18_A0000_FLUSH_EN (1<<1) +#define GR18_SMM_EN (1<<0) + +/* Set by driver, cleared by VBIOS */ +#define SWF00_YRES_SHIFT 16 +#define SWF00_XRES_SHIFT 0 +#define SWF00_RES_MASK 0xffff + +/* Set by VBIOS at boot time and driver at runtime */ +#define SWF01_TV2_FORMAT_SHIFT 8 +#define SWF01_TV1_FORMAT_SHIFT 0 +#define SWF01_TV_FORMAT_MASK 0xffff + +#define SWF10_VBIOS_BLC_I2C_EN (1<<29) +#define SWF10_GTT_OVERRIDE_EN (1<<28) +#define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */ +#define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24) +#define SWF10_OLD_TOGGLE 0x0 +#define SWF10_TOGGLE_LIST_1 0x1 +#define SWF10_TOGGLE_LIST_2 0x2 +#define SWF10_TOGGLE_LIST_3 0x3 +#define SWF10_TOGGLE_LIST_4 0x4 +#define SWF10_PANNING_EN (1<<23) +#define SWF10_DRIVER_LOADED (1<<22) +#define SWF10_EXTENDED_DESKTOP (1<<21) +#define SWF10_EXCLUSIVE_MODE (1<<20) +#define SWF10_OVERLAY_EN (1<<19) +#define SWF10_PLANEB_HOLDOFF (1<<18) +#define SWF10_PLANEA_HOLDOFF (1<<17) +#define SWF10_VGA_HOLDOFF (1<<16) +#define SWF10_ACTIVE_DISP_MASK 0xffff +#define SWF10_PIPEB_LFP2 (1<<15) +#define SWF10_PIPEB_EFP2 (1<<14) +#define SWF10_PIPEB_TV2 (1<<13) +#define SWF10_PIPEB_CRT2 (1<<12) +#define SWF10_PIPEB_LFP (1<<11) +#define SWF10_PIPEB_EFP (1<<10) +#define SWF10_PIPEB_TV (1<<9) +#define SWF10_PIPEB_CRT (1<<8) +#define SWF10_PIPEA_LFP2 (1<<7) +#define SWF10_PIPEA_EFP2 (1<<6) +#define SWF10_PIPEA_TV2 (1<<5) +#define SWF10_PIPEA_CRT2 (1<<4) +#define SWF10_PIPEA_LFP (1<<3) +#define SWF10_PIPEA_EFP (1<<2) +#define SWF10_PIPEA_TV (1<<1) +#define SWF10_PIPEA_CRT (1<<0) + +#define SWF11_MEMORY_SIZE_SHIFT 16 +#define SWF11_SV_TEST_EN (1<<15) +#define SWF11_IS_AGP (1<<14) +#define SWF11_DISPLAY_HOLDOFF (1<<13) +#define SWF11_DPMS_REDUCED (1<<12) +#define SWF11_IS_VBE_MODE (1<<11) +#define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */ +#define SWF11_DPMS_MASK 0x07 +#define SWF11_DPMS_OFF (1<<2) +#define SWF11_DPMS_SUSPEND (1<<1) +#define SWF11_DPMS_STANDBY (1<<0) +#define SWF11_DPMS_ON 0 + +#define SWF14_GFX_PFIT_EN (1<<31) +#define SWF14_TEXT_PFIT_EN (1<<30) +#define SWF14_LID_SWITCH_EN (1<<29) +#define SWF14_POPUP_EN (1<<28) +#define SWF14_DISPLAY_HOLDOFF (1<<27) +#define SWF14_DISP_DETECT_EN (1<<26) +#define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */ +#define SWF14_DRIVER_STATUS (1<<24) +#define SWF14_OS_TYPE_WIN9X (1<<23) +#define SWF14_OS_TYPE_WINNT (1<<22) +/* 21:19 rsvd */ +#define SWF14_PM_TYPE_MASK 0x00070000 +#define SWF14_PM_ACPI_VIDEO (0x4 << 16) +#define SWF14_PM_ACPI (0x3 << 16) +#define SWF14_PM_APM_12 (0x2 << 16) +#define SWF14_PM_APM_11 (0x1 << 16) +#define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */ + /* if GR18 indicates a display switch */ +#define SWF14_DS_PIPEB_LFP2_EN (1<<15) +#define SWF14_DS_PIPEB_EFP2_EN (1<<14) +#define SWF14_DS_PIPEB_TV2_EN (1<<13) +#define SWF14_DS_PIPEB_CRT2_EN (1<<12) +#define SWF14_DS_PIPEB_LFP_EN (1<<11) +#define SWF14_DS_PIPEB_EFP_EN (1<<10) +#define SWF14_DS_PIPEB_TV_EN (1<<9) +#define SWF14_DS_PIPEB_CRT_EN (1<<8) +#define SWF14_DS_PIPEA_LFP2_EN (1<<7) +#define SWF14_DS_PIPEA_EFP2_EN (1<<6) +#define SWF14_DS_PIPEA_TV2_EN (1<<5) +#define SWF14_DS_PIPEA_CRT2_EN (1<<4) +#define SWF14_DS_PIPEA_LFP_EN (1<<3) +#define SWF14_DS_PIPEA_EFP_EN (1<<2) +#define SWF14_DS_PIPEA_TV_EN (1<<1) +#define SWF14_DS_PIPEA_CRT_EN (1<<0) + /* if GR18 indicates a panel fitting request */ +#define SWF14_PFIT_EN (1<<0) /* 0 means disable */ + /* if GR18 indicates an APM change request */ +#define SWF14_APM_HIBERNATE 0x4 +#define SWF14_APM_SUSPEND 0x3 +#define SWF14_APM_STANDBY 0x1 +#define SWF14_APM_RESTORE 0x0 + +#endif /* _INTEL_BIOS_H_ */ diff --git a/tools/intel_bios_dumper.c b/tools/intel_bios_dumper.c new file mode 100644 index 00000000..6455689f --- /dev/null +++ b/tools/intel_bios_dumper.c @@ -0,0 +1,112 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <pciaccess.h> +#include <err.h> + +#ifndef DEFFILEMODE +#define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /* 0666 */ +#endif + +static void usage(void) +{ + fprintf(stderr, "usage: bios_dumper <filename>\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + struct pci_device *dev; + void *bios; + int error, fd; + + if (argc != 2) + usage(); + + error = pci_system_init(); + if (error != 0) { + fprintf(stderr, "Couldn't initialize PCI system: %s\n", + strerror(error)); + exit(1); + } + + /* Grab the graphics card */ + dev = pci_device_find_by_slot(0, 0, 2, 0); + if (dev == NULL) + errx(1, "Couldn't find graphics card"); + + error = pci_device_probe(dev); + if (error != 0) { + fprintf(stderr, "Couldn't probe graphics card: %s\n", + strerror(error)); + exit(1); + } + + if (dev->vendor_id != 0x8086) + errx(1, "Graphics card is non-intel"); + + /* Some versions of libpciaccess correct this automatically, but some + * don't. */ + if (dev->rom_size == 0) + dev->rom_size = 64 * 1024; + + bios = malloc(dev->rom_size); + if (bios == NULL) + errx(1, "Couldn't allocate memory for BIOS data\n"); + + error = pci_device_read_rom(dev, bios); + if (error != 0) { + fprintf(stderr, "Couldn't read graphics card ROM: %s\n", + strerror(error)); + exit(1); + } + + fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, DEFFILEMODE); + if (fd < 0) { + fprintf(stderr, "Couldn't open output: %s\n", strerror(errno)); + exit(1); + } + + if (write(fd, bios, dev->rom_size) < dev->rom_size) { + fprintf(stderr, "Couldn't write BIOS data: %s\n", + strerror(errno)); + exit(1); + } + + close(fd); + pci_system_cleanup(); + + return 0; +} diff --git a/tools/intel_bios_reader.c b/tools/intel_bios_reader.c new file mode 100644 index 00000000..493fb637 --- /dev/null +++ b/tools/intel_bios_reader.c @@ -0,0 +1,947 @@ +/* + * Copyright 2006 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "intel_bios.h" +#include "intel_gpu_tools.h" + +static uint32_t devid = -1; + +/* no bother to include "edid.h" */ +#define _H_ACTIVE(x) (x[2] + ((x[4] & 0xF0) << 4)) +#define _H_SYNC_OFF(x) (x[8] + ((x[11] & 0xC0) << 2)) +#define _H_SYNC_WIDTH(x) (x[9] + ((x[11] & 0x30) << 4)) +#define _H_BLANK(x) (x[3] + ((x[4] & 0x0F) << 8)) +#define _V_ACTIVE(x) (x[5] + ((x[7] & 0xF0) << 4)) +#define _V_SYNC_OFF(x) ((x[10] >> 4) + ((x[11] & 0x0C) << 2)) +#define _V_SYNC_WIDTH(x) ((x[10] & 0x0F) + ((x[11] & 0x03) << 4)) +#define _V_BLANK(x) (x[6] + ((x[7] & 0x0F) << 8)) +#define _PIXEL_CLOCK(x) (x[0] + (x[1] << 8)) * 10000 + +uint8_t *VBIOS; + +#define INTEL_BIOS_8(_addr) (VBIOS[_addr]) +#define INTEL_BIOS_16(_addr) (VBIOS[_addr] | \ + (VBIOS[_addr + 1] << 8)) +#define INTEL_BIOS_32(_addr) (VBIOS[_addr] | \ + (VBIOS[_addr + 1] << 8) | \ + (VBIOS[_addr + 2] << 16) | \ + (VBIOS[_addr + 3] << 24)) + +#define YESNO(val) ((val) ? "yes" : "no") + +struct bdb_block { + uint8_t id; + uint16_t size; + void *data; +}; + +struct bdb_header *bdb; +static int tv_present; +static int lvds_present; +static int panel_type; + +static struct bdb_block *find_section(int section_id, int length) +{ + struct bdb_block *block; + unsigned char *base = (unsigned char *)bdb; + int idx = 0; + uint16_t total, current_size; + unsigned char current_id; + + /* skip to first section */ + idx += bdb->header_size; + total = bdb->bdb_size; + if (total > length) + total = length; + + block = malloc(sizeof(*block)); + if (!block) { + fprintf(stderr, "out of memory\n"); + exit(-1); + } + + /* walk the sections looking for section_id */ + while (idx + 3 < total) { + current_id = *(base + idx); + current_size = *(uint16_t *)(base + idx + 1); + if (idx + current_size > total) + return NULL; + + if (current_id == section_id) { + block->id = current_id; + block->size = current_size; + block->data = base + idx + 3; + return block; + } + + idx += current_size + 3; + } + + free(block); + return NULL; +} + +static void dump_general_features(int length) +{ + struct bdb_general_features *features; + struct bdb_block *block; + + block = find_section(BDB_GENERAL_FEATURES, length); + + if (!block) + return; + + features = block->data; + + printf("General features block:\n"); + + printf("\tPanel fitting: "); + switch (features->panel_fitting) { + case 0: + printf("disabled\n"); + break; + case 1: + printf("text only\n"); + break; + case 2: + printf("graphics only\n"); + break; + case 3: + printf("text & graphics\n"); + break; + } + printf("\tFlexaim: %s\n", YESNO(features->flexaim)); + printf("\tMessage: %s\n", YESNO(features->msg_enable)); + printf("\tClear screen: %d\n", features->clear_screen); + printf("\tDVO color flip required: %s\n", YESNO(features->color_flip)); + printf("\tExternal VBT: %s\n", YESNO(features->download_ext_vbt)); + printf("\tEnable SSC: %s\n", YESNO(features->enable_ssc)); + if (features->enable_ssc) { + if (HAS_PCH_SPLIT(devid)) + printf("\tSSC frequency: %s\n", features->ssc_freq ? + "100 MHz" : "120 MHz"); + else + printf("\tSSC frequency: %s\n", features->ssc_freq ? + "100 MHz (66 MHz on 855)" : "96 MHz (48 MHz on 855)"); + } + printf("\tLFP on override: %s\n", + YESNO(features->enable_lfp_on_override)); + printf("\tDisable SSC on clone: %s\n", + YESNO(features->disable_ssc_ddt)); + printf("\tDisable smooth vision: %s\n", + YESNO(features->disable_smooth_vision)); + printf("\tSingle DVI for CRT/DVI: %s\n", YESNO(features->single_dvi)); + printf("\tLegacy monitor detect: %s\n", + YESNO(features->legacy_monitor_detect)); + printf("\tIntegrated CRT: %s\n", YESNO(features->int_crt_support)); + printf("\tIntegrated TV: %s\n", YESNO(features->int_tv_support)); + + tv_present = 1; /* should be based on whether TV DAC exists */ + lvds_present = 1; /* should be based on IS_MOBILE() */ + + free(block); +} + +static void dump_backlight_info(int length) +{ + struct bdb_block *block; + struct bdb_lvds_backlight *backlight; + struct blc_struct *blc; + + block = find_section(BDB_LVDS_BACKLIGHT, length); + + if (!block) + return; + + backlight = block->data; + + printf("Backlight info block (len %d):\n", block->size); + + if (sizeof(struct blc_struct) != backlight->blcstruct_size) { + printf("\tBacklight struct sizes don't match (expected %zu, got %u), skipping\n", + sizeof(struct blc_struct), backlight->blcstruct_size); + return; + } + + blc = &backlight->panels[panel_type]; + + printf("\tInverter type: %d\n", blc->inverter_type); + printf("\t polarity: %d\n", blc->inverter_polarity); + printf("\t GPIO pins: %d\n", blc->gpio_pins); + printf("\t GMBUS speed: %d\n", blc->gmbus_speed); + printf("\t PWM freq: %d\n", blc->pwm_freq); + printf("\tMinimum brightness: %d\n", blc->min_brightness); + printf("\tI2C slave addr: 0x%02x\n", blc->i2c_slave_addr); + printf("\tI2C command: 0x%02x\n", blc->i2c_cmd); +} + +static const struct { + unsigned short type; + const char *name; +} child_device_types[] = { + { DEVICE_TYPE_NONE, "none" }, + { DEVICE_TYPE_CRT, "CRT" }, + { DEVICE_TYPE_TV, "TV" }, + { DEVICE_TYPE_EFP, "EFP" }, + { DEVICE_TYPE_LFP, "LFP" }, + { DEVICE_TYPE_CRT_DPMS, "CRT" }, + { DEVICE_TYPE_CRT_DPMS_HOTPLUG, "CRT" }, + { DEVICE_TYPE_TV_COMPOSITE, "TV composite" }, + { DEVICE_TYPE_TV_MACROVISION, "TV" }, + { DEVICE_TYPE_TV_RF_COMPOSITE, "TV" }, + { DEVICE_TYPE_TV_SVIDEO_COMPOSITE, "TV S-Video" }, + { DEVICE_TYPE_TV_SCART, "TV SCART" }, + { DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR, "TV" }, + { DEVICE_TYPE_EFP_HOTPLUG_PWR, "EFP" }, + { DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR, "DVI" }, + { DEVICE_TYPE_EFP_DVI_I, "DVI-I" }, + { DEVICE_TYPE_EFP_DVI_D_DUAL, "DL-DVI-D" }, + { DEVICE_TYPE_EFP_DVI_D_HDCP, "DVI-D" }, + { DEVICE_TYPE_OPENLDI_HOTPLUG_PWR, "OpenLDI" }, + { DEVICE_TYPE_OPENLDI_DUALPIX, "OpenLDI" }, + { DEVICE_TYPE_LFP_PANELLINK, "PanelLink" }, + { DEVICE_TYPE_LFP_CMOS_PWR, "CMOS LFP" }, + { DEVICE_TYPE_LFP_LVDS_PWR, "LVDS" }, + { DEVICE_TYPE_LFP_LVDS_DUAL, "LVDS" }, + { DEVICE_TYPE_LFP_LVDS_DUAL_HDCP, "LVDS" }, + { DEVICE_TYPE_INT_LFP, "LFP" }, + { DEVICE_TYPE_INT_TV, "TV" }, + { DEVICE_TYPE_DP, "DisplayPort" }, + { DEVICE_TYPE_DP_HDMI_DVI, "DisplayPort/HDMI/DVI" }, + { DEVICE_TYPE_DP_DVI, "DisplayPort/DVI" }, + { DEVICE_TYPE_HDMI_DVI, "HDMI/DVI" }, + { DEVICE_TYPE_DVI, "DVI" }, + { DEVICE_TYPE_eDP, "eDP" }, +}; +static const int num_child_device_types = + sizeof(child_device_types) / sizeof(child_device_types[0]); + +static const char *child_device_type(unsigned short type) +{ + int i; + + for (i = 0; i < num_child_device_types; i++) + if (child_device_types[i].type == type) + return child_device_types[i].name; + + return "unknown"; +} + +static const struct { + unsigned short type; + const char *name; +} efp_ports[] = { + { DEVICE_PORT_NONE, "N/A" }, + { DEVICE_PORT_HDMIB, "HDMI-B" }, + { DEVICE_PORT_HDMIC, "HDMI-C" }, + { DEVICE_PORT_HDMID, "HDMI-D" }, + { DEVICE_PORT_DPB, "DP-B" }, + { DEVICE_PORT_DPC, "DP-C" }, + { DEVICE_PORT_DPD, "DP-D" }, +}; +static const int num_efp_ports = sizeof(efp_ports) / sizeof(efp_ports[0]); + +static const char *efp_port(uint8_t type) +{ + int i; + + for (i = 0; i < num_efp_ports; i++) + if (efp_ports[i].type == type) + return efp_ports[i].name; + + return "unknown"; +} + +static const struct { + unsigned short type; + const char *name; +} efp_conn_info[] = { + { DEVICE_INFO_NONE, "N/A" }, + { DEVICE_INFO_HDMI_CERT, "HDMI certified" }, + { DEVICE_INFO_DP, "DisplayPort" }, + { DEVICE_INFO_DVI, "DVI" }, +}; +static const int num_efp_conn_info = sizeof(efp_conn_info) / sizeof(efp_conn_info[0]); + +static const char *efp_conn(uint8_t type) +{ + int i; + + for (i = 0; i < num_efp_conn_info; i++) + if (efp_conn_info[i].type == type) + return efp_conn_info[i].name; + + return "unknown"; +} + + + +static void dump_child_device(struct child_device_config *child) +{ + char child_id[11]; + + if (!child->device_type) + return; + + if (bdb->version < 152) { + strncpy(child_id, (char *)child->device_id, 10); + child_id[10] = 0; + + printf("\tChild device info:\n"); + printf("\t\tDevice type: %04x (%s)\n", child->device_type, + child_device_type(child->device_type)); + printf("\t\tSignature: %s\n", child_id); + printf("\t\tAIM offset: %d\n", child->addin_offset); + printf("\t\tDVO port: 0x%02x\n", child->dvo_port); + } else { /* 152+ have EFP blocks here */ + struct efp_child_device_config *efp = + (struct efp_child_device_config *)child; + printf("\tEFP device info:\n"); + printf("\t\tDevice type: 0x%04x (%s)\n", efp->device_type, + child_device_type(efp->device_type)); + printf("\t\tPort: 0x%02x (%s)\n", efp->port, + efp_port(efp->port)); + printf("\t\tDDC pin: 0x%02x\n", efp->ddc_pin); + printf("\t\tDock port: 0x%02x (%s)\n", efp->docked_port, + efp_port(efp->docked_port)); + printf("\t\tHDMI compatible? %s\n", efp->hdmi_compat ? "Yes" : "No"); + printf("\t\tInfo: %s\n", efp_conn(efp->conn_info)); + printf("\t\tAux channel: 0x%02x\n", efp->aux_chan); + printf("\t\tDongle detect: 0x%02x\n", efp->dongle_detect); + } +} + +static void dump_general_definitions(int length) +{ + struct bdb_block *block; + struct bdb_general_definitions *defs; + struct child_device_config *child; + int i; + int child_device_num; + + block = find_section(BDB_GENERAL_DEFINITIONS, length); + + if (!block) + return; + + defs = block->data; + + printf("General definitions block:\n"); + + printf("\tCRT DDC GMBUS addr: 0x%02x\n", defs->crt_ddc_gmbus_pin); + printf("\tUse ACPI DPMS CRT power states: %s\n", + YESNO(defs->dpms_acpi)); + printf("\tSkip CRT detect at boot: %s\n", + YESNO(defs->skip_boot_crt_detect)); + printf("\tUse DPMS on AIM devices: %s\n", YESNO(defs->dpms_aim)); + printf("\tBoot display type: 0x%02x%02x\n", defs->boot_display[1], + defs->boot_display[0]); + printf("\tTV data block present: %s\n", YESNO(tv_present)); + child_device_num = (block->size - sizeof(*defs)) / sizeof(*child); + for (i = 0; i < child_device_num; i++) + dump_child_device(&defs->devices[i]); + free(block); +} + +static void dump_child_devices(int length) +{ + struct bdb_block *block; + struct bdb_child_devices *child_devs; + struct child_device_config *child; + int i; + + block = find_section(BDB_CHILD_DEVICE_TABLE, length); + if (!block) { + printf("No child device table found\n"); + return; + } + + child_devs = block->data; + + printf("Child devices block:\n"); + for (i = 0; i < DEVICE_CHILD_SIZE; i++) { + child = &child_devs->children[i]; + /* Skip nonexistent children */ + if (!child->device_type) + continue; + printf("\tChild device %d\n", i); + printf("\t\tType: 0x%04x (%s)\n", child->device_type, + child_device_type(child->device_type)); + printf("\t\tDVO port: 0x%02x\n", child->dvo_port); + printf("\t\tI2C pin: 0x%02x\n", child->i2c_pin); + printf("\t\tSlave addr: 0x%02x\n", child->slave_addr); + printf("\t\tDDC pin: 0x%02x\n", child->ddc_pin); + printf("\t\tDVO config: 0x%02x\n", child->dvo_cfg); + printf("\t\tDVO wiring: 0x%02x\n", child->dvo_wiring); + } + + free(block); +} + +static void dump_lvds_options(int length) +{ + struct bdb_block *block; + struct bdb_lvds_options *options; + + block = find_section(BDB_LVDS_OPTIONS, length); + if (!block) { + printf("No LVDS options block\n"); + return; + } + + options = block->data; + + printf("LVDS options block:\n"); + + panel_type = options->panel_type; + printf("\tPanel type: %d\n", panel_type); + printf("\tLVDS EDID available: %s\n", YESNO(options->lvds_edid)); + printf("\tPixel dither: %s\n", YESNO(options->pixel_dither)); + printf("\tPFIT auto ratio: %s\n", YESNO(options->pfit_ratio_auto)); + printf("\tPFIT enhanced graphics mode: %s\n", + YESNO(options->pfit_gfx_mode_enhanced)); + printf("\tPFIT enhanced text mode: %s\n", + YESNO(options->pfit_text_mode_enhanced)); + printf("\tPFIT mode: %d\n", options->pfit_mode); + + free(block); +} + +static void dump_lvds_ptr_data(int length) +{ + struct bdb_block *block; + struct bdb_lvds_lfp_data *lvds_data; + struct bdb_lvds_lfp_data_ptrs *ptrs; + struct lvds_fp_timing *fp_timing; + struct bdb_lvds_lfp_data_entry *entry; + int lfp_data_size; + + block = find_section(BDB_LVDS_LFP_DATA_PTRS, length); + if (!block) { + printf("No LFP data pointers block\n"); + return; + } + ptrs = block->data; + + block = find_section(BDB_LVDS_LFP_DATA, length); + if (!block) { + printf("No LVDS data block\n"); + return; + } + lvds_data = block->data; + + lfp_data_size = + ptrs->ptr[1].fp_timing_offset - ptrs->ptr[0].fp_timing_offset; + entry = + (struct bdb_lvds_lfp_data_entry *)((uint8_t *) lvds_data->data + + (lfp_data_size * panel_type)); + fp_timing = &entry->fp_timing; + + printf("LVDS timing pointer data:\n"); + printf(" Number of entries: %d\n", ptrs->lvds_entries); + + printf("\tpanel type %02i: %dx%d\n", panel_type, fp_timing->x_res, + fp_timing->y_res); + + free(block); +} + +static void dump_lvds_data(int length) +{ + struct bdb_block *block; + struct bdb_lvds_lfp_data *lvds_data; + struct bdb_lvds_lfp_data_ptrs *ptrs; + int num_entries; + int i; + int hdisplay, hsyncstart, hsyncend, htotal; + int vdisplay, vsyncstart, vsyncend, vtotal; + float clock; + int lfp_data_size, dvo_offset; + + block = find_section(BDB_LVDS_LFP_DATA_PTRS, length); + if (!block) { + printf("No LVDS ptr block\n"); + return; + } + ptrs = block->data; + lfp_data_size = + ptrs->ptr[1].fp_timing_offset - ptrs->ptr[0].fp_timing_offset; + dvo_offset = + ptrs->ptr[0].dvo_timing_offset - ptrs->ptr[0].fp_timing_offset; + free(block); + + block = find_section(BDB_LVDS_LFP_DATA, length); + if (!block) { + printf("No LVDS data block\n"); + return; + } + + lvds_data = block->data; + num_entries = block->size / lfp_data_size; + + printf("LVDS panel data block (preferred block marked with '*'):\n"); + printf(" Number of entries: %d\n", num_entries); + + for (i = 0; i < num_entries; i++) { + uint8_t *lfp_data_ptr = + (uint8_t *) lvds_data->data + lfp_data_size * i; + uint8_t *timing_data = lfp_data_ptr + dvo_offset; + struct bdb_lvds_lfp_data_entry *lfp_data = + (struct bdb_lvds_lfp_data_entry *)lfp_data_ptr; + char marker; + + if (i == panel_type) + marker = '*'; + else + marker = ' '; + + hdisplay = _H_ACTIVE(timing_data); + hsyncstart = hdisplay + _H_SYNC_OFF(timing_data); + hsyncend = hsyncstart + _H_SYNC_WIDTH(timing_data); + htotal = hdisplay + _H_BLANK(timing_data); + + vdisplay = _V_ACTIVE(timing_data); + vsyncstart = vdisplay + _V_SYNC_OFF(timing_data); + vsyncend = vsyncstart + _V_SYNC_WIDTH(timing_data); + vtotal = vdisplay + _V_BLANK(timing_data); + clock = _PIXEL_CLOCK(timing_data) / 1000; + + printf("%c\tpanel type %02i: %dx%d clock %d\n", marker, + i, lfp_data->fp_timing.x_res, lfp_data->fp_timing.y_res, + _PIXEL_CLOCK(timing_data)); + printf("\t\tinfo:\n"); + printf("\t\t LVDS: 0x%08lx\n", + (unsigned long)lfp_data->fp_timing.lvds_reg_val); + printf("\t\t PP_ON_DELAYS: 0x%08lx\n", + (unsigned long)lfp_data->fp_timing.pp_on_reg_val); + printf("\t\t PP_OFF_DELAYS: 0x%08lx\n", + (unsigned long)lfp_data->fp_timing.pp_off_reg_val); + printf("\t\t PP_DIVISOR: 0x%08lx\n", + (unsigned long)lfp_data->fp_timing.pp_cycle_reg_val); + printf("\t\t PFIT: 0x%08lx\n", + (unsigned long)lfp_data->fp_timing.pfit_reg_val); + printf("\t\ttimings: %d %d %d %d %d %d %d %d %.2f (%s)\n", + hdisplay, hsyncstart, hsyncend, htotal, + vdisplay, vsyncstart, vsyncend, vtotal, clock, + (hsyncend > htotal || vsyncend > vtotal) ? + "BAD!" : "good"); + } + free(block); +} + +static void dump_driver_feature(int length) +{ + struct bdb_block *block; + struct bdb_driver_feature *feature; + + block = find_section(BDB_DRIVER_FEATURES, length); + if (!block) { + printf("No Driver feature data block\n"); + return; + } + feature = block->data; + + printf("Driver feature Data Block:\n"); + printf("\tBoot Device Algorithm: %s\n", feature->boot_dev_algorithm ? + "driver default" : "os default"); + printf("\tBlock display switching when DVD active: %s\n", + YESNO(feature->block_display_switch)); + printf("\tAllow display switching when in Full Screen DOS: %s\n", + YESNO(feature->allow_display_switch)); + printf("\tHot Plug DVO: %s\n", YESNO(feature->hotplug_dvo)); + printf("\tDual View Zoom: %s\n", YESNO(feature->dual_view_zoom)); + printf("\tDriver INT 15h hook: %s\n", YESNO(feature->int15h_hook)); + printf("\tEnable Sprite in Clone Mode: %s\n", + YESNO(feature->sprite_in_clone)); + printf("\tUse 00000110h ID for Primary LFP: %s\n", + YESNO(feature->primary_lfp_id)); + printf("\tBoot Mode X: %u\n", feature->boot_mode_x); + printf("\tBoot Mode Y: %u\n", feature->boot_mode_y); + printf("\tBoot Mode Bpp: %u\n", feature->boot_mode_bpp); + printf("\tBoot Mode Refresh: %u\n", feature->boot_mode_refresh); + printf("\tEnable LFP as primary: %s\n", + YESNO(feature->enable_lfp_primary)); + printf("\tSelective Mode Pruning: %s\n", + YESNO(feature->selective_mode_pruning)); + printf("\tDual-Frequency Graphics Technology: %s\n", + YESNO(feature->dual_frequency)); + printf("\tDefault Render Clock Frequency: %s\n", + feature->render_clock_freq ? "low" : "high"); + printf("\tNT 4.0 Dual Display Clone Support: %s\n", + YESNO(feature->nt_clone_support)); + printf("\tDefault Power Scheme user interface: %s\n", + feature->power_scheme_ui ? "3rd party" : "CUI"); + printf + ("\tSprite Display Assignment when Overlay is Active in Clone Mode: %s\n", + feature->sprite_display_assign ? "primary" : "secondary"); + printf("\tDisplay Maintain Aspect Scaling via CUI: %s\n", + YESNO(feature->cui_aspect_scaling)); + printf("\tPreserve Aspect Ratio: %s\n", + YESNO(feature->preserve_aspect_ratio)); + printf("\tEnable SDVO device power down: %s\n", + YESNO(feature->sdvo_device_power_down)); + printf("\tCRT hotplug: %s\n", YESNO(feature->crt_hotplug)); + printf("\tLVDS config: "); + switch (feature->lvds_config) { + case BDB_DRIVER_NO_LVDS: + printf("No LVDS\n"); + break; + case BDB_DRIVER_INT_LVDS: + printf("Integrated LVDS\n"); + break; + case BDB_DRIVER_SDVO_LVDS: + printf("SDVO LVDS\n"); + break; + case BDB_DRIVER_EDP: + printf("Embedded DisplayPort\n"); + break; + } + printf("\tDefine Display statically: %s\n", + YESNO(feature->static_display)); + printf("\tLegacy CRT max X: %d\n", feature->legacy_crt_max_x); + printf("\tLegacy CRT max Y: %d\n", feature->legacy_crt_max_y); + printf("\tLegacy CRT max refresh: %d\n", + feature->legacy_crt_max_refresh); + free(block); +} + +static void dump_edp(int length) +{ + struct bdb_block *block; + struct bdb_edp *edp; + int bpp; + + block = find_section(BDB_EDP, length); + if (!block) { + printf("No EDP data block\n"); + return; + } + edp = block->data; + + printf("eDP block: type %d\n", panel_type); + printf("\tPower Sequence: T3 %d T7 %d T9 %d T10 %d T12 %d\n", + edp->power_seqs[panel_type].t3, + edp->power_seqs[panel_type].t7, + edp->power_seqs[panel_type].t9, + edp->power_seqs[panel_type].t10, + edp->power_seqs[panel_type].t12); + + bpp = (edp->color_depth >> (panel_type * 2)) & 3; + + printf("\tPanel color depth: "); + switch (bpp) { + case EDP_18BPP: + printf("18bpp\n"); + break; + case EDP_24BPP: + printf("24bpp\n"); + break; + case EDP_30BPP: + printf("30bpp\n"); + break; + } + printf("\teDP sDRRs MSA timing delay: %d\n", edp->sdrrs_msa_timing_delay); + printf("\tLink params:\n"); + printf("\t\trate: "); + if (edp->link_params[panel_type].rate == EDP_RATE_1_62) + printf("1.62G\n"); + else if (edp->link_params[panel_type].rate == EDP_RATE_2_7) + printf("2.7G\n"); + printf("\t\tlanes: "); + switch (edp->link_params[panel_type].lanes) { + case EDP_LANE_1: + printf("x1 mode\n"); + break; + case EDP_LANE_2: + printf("x2 mode\n"); + break; + case EDP_LANE_4: + printf("x4 mode\n"); + break; + } + printf("\t\tpre-emphasis: "); + switch (edp->link_params[panel_type].preemphasis) { + case EDP_PREEMPHASIS_NONE: + printf("none\n"); + break; + case EDP_PREEMPHASIS_3_5dB: + printf("3.5dB\n"); + break; + case EDP_PREEMPHASIS_6dB: + printf("6dB\n"); + break; + case EDP_PREEMPHASIS_9_5dB: + printf("9.5dB\n"); + break; + } + printf("\t\tvswing: "); + switch (edp->link_params[panel_type].vswing) { + case EDP_VSWING_0_4V: + printf("0.4V\n"); + break; + case EDP_VSWING_0_6V: + printf("0.6V\n"); + break; + case EDP_VSWING_0_8V: + printf("0.8V\n"); + break; + case EDP_VSWING_1_2V: + printf("1.2V\n"); + break; + } + free(block); +} + +static void +print_detail_timing_data(struct lvds_dvo_timing2 *dvo_timing) +{ + int display, sync_start, sync_end, total; + + display = (dvo_timing->hactive_hi << 8) | dvo_timing->hactive_lo; + sync_start = display + + ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); + sync_end = sync_start + dvo_timing->hsync_pulse_width; + total = display + + ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); + printf("\thdisplay: %d\n", display); + printf("\thsync [%d, %d] %s\n", sync_start, sync_end, + dvo_timing->hsync_positive ? "+sync" : "-sync"); + printf("\thtotal: %d\n", total); + + display = (dvo_timing->vactive_hi << 8) | dvo_timing->vactive_lo; + sync_start = display + dvo_timing->vsync_off; + sync_end = sync_start + dvo_timing->vsync_pulse_width; + total = display + + ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); + printf("\tvdisplay: %d\n", display); + printf("\tvsync [%d, %d] %s\n", sync_start, sync_end, + dvo_timing->vsync_positive ? "+sync" : "-sync"); + printf("\tvtotal: %d\n", total); + + printf("\tclock: %d\n", dvo_timing->clock * 10); +} + +static void dump_sdvo_panel_dtds(int length) +{ + struct bdb_block *block; + struct lvds_dvo_timing2 *dvo_timing; + int n, count; + + block = find_section(BDB_SDVO_PANEL_DTDS, length); + if (!block) { + printf("No SDVO panel dtds block\n"); + return; + } + + printf("SDVO panel dtds:\n"); + count = block->size / sizeof(struct lvds_dvo_timing2); + dvo_timing = block->data; + for (n = 0; n < count; n++) { + printf("%d:\n", n); + print_detail_timing_data(dvo_timing++); + } + + free(block); +} + +static void dump_sdvo_lvds_options(int length) +{ + struct bdb_block *block; + struct bdb_sdvo_lvds_options *options; + + block = find_section(BDB_SDVO_LVDS_OPTIONS, length); + if (!block) { + printf("No SDVO LVDS options block\n"); + return; + } + + options = block->data; + + printf("SDVO LVDS options block:\n"); + printf("\tbacklight: %d\n", options->panel_backlight); + printf("\th40 type: %d\n", options->h40_set_panel_type); + printf("\ttype: %d\n", options->panel_type); + printf("\tssc_clk_freq: %d\n", options->ssc_clk_freq); + printf("\tals_low_trip: %d\n", options->als_low_trip); + printf("\tals_high_trip: %d\n", options->als_high_trip); + /* + u8 sclalarcoeff_tab_row_num; + u8 sclalarcoeff_tab_row_size; + u8 coefficient[8]; + */ + printf("\tmisc[0]: %x\n", options->panel_misc_bits_1); + printf("\tmisc[1]: %x\n", options->panel_misc_bits_2); + printf("\tmisc[2]: %x\n", options->panel_misc_bits_3); + printf("\tmisc[3]: %x\n", options->panel_misc_bits_4); + + free(block); +} + +static int +get_device_id(unsigned char *bios) +{ + int device; + int offset = (bios[0x19] << 8) + bios[0x18]; + + if (bios[offset] != 'P' || + bios[offset+1] != 'C' || + bios[offset+2] != 'I' || + bios[offset+3] != 'R') + return -1; + + device = (bios[offset+7] << 8) + bios[offset+6]; + + return device; +} + +int main(int argc, char **argv) +{ + int fd; + struct vbt_header *vbt = NULL; + int vbt_off, bdb_off, i; + const char *filename = "bios"; + struct stat finfo; + struct bdb_block *block; + char signature[17]; + char *devid_string; + + if (argc != 2) { + printf("usage: %s <rom file>\n", argv[0]); + return 1; + } + + if ((devid_string = getenv("DEVICE"))) + devid = strtoul(devid_string, NULL, 0); + + filename = argv[1]; + + fd = open(filename, O_RDONLY); + if (fd == -1) { + printf("Couldn't open \"%s\": %s\n", filename, strerror(errno)); + return 1; + } + + if (stat(filename, &finfo)) { + printf("failed to stat \"%s\": %s\n", filename, + strerror(errno)); + return 1; + } + + if (finfo.st_size == 0) { + int len = 0, ret; + finfo.st_size = 8192; + VBIOS = malloc (finfo.st_size); + while ((ret = read(fd, VBIOS + len, finfo.st_size - len))) { + if (ret < 0) { + printf("failed to read \"%s\": %s\n", filename, + strerror(errno)); + return 1; + } + + len += ret; + if (len == finfo.st_size) { + finfo.st_size *= 2; + VBIOS = realloc(VBIOS, finfo.st_size); + } + } + } else { + VBIOS = mmap(NULL, finfo.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (VBIOS == MAP_FAILED) { + printf("failed to map \"%s\": %s\n", filename, strerror(errno)); + return 1; + } + } + + /* Scour memory looking for the VBT signature */ + for (i = 0; i + 4 < finfo.st_size; i++) { + if (!memcmp(VBIOS + i, "$VBT", 4)) { + vbt_off = i; + vbt = (struct vbt_header *)(VBIOS + i); + break; + } + } + + if (!vbt) { + printf("VBT signature missing\n"); + return 1; + } + + printf("VBT vers: %d.%d\n", vbt->version / 100, vbt->version % 100); + + bdb_off = vbt_off + vbt->bdb_offset; + if (bdb_off >= finfo.st_size - sizeof(struct bdb_header)) { + printf("Invalid VBT found, BDB points beyond end of data block\n"); + return 1; + } + + bdb = (struct bdb_header *)(VBIOS + bdb_off); + strncpy(signature, (char *)bdb->signature, 16); + signature[16] = 0; + printf("BDB sig: %s\n", signature); + printf("BDB vers: %d\n", bdb->version); + + printf("Available sections: "); + for (i = 0; i < 256; i++) { + block = find_section(i, finfo.st_size); + if (!block) + continue; + printf("%d ", i); + free(block); + } + printf("\n"); + + if (devid == -1) + devid = get_device_id(VBIOS); + if (devid == -1) + printf("Warning: could not find PCI device ID!\n"); + + dump_general_features(finfo.st_size); + dump_general_definitions(finfo.st_size); + dump_child_devices(finfo.st_size); + dump_lvds_options(finfo.st_size); + dump_lvds_data(finfo.st_size); + dump_lvds_ptr_data(finfo.st_size); + dump_backlight_info(finfo.st_size); + + dump_sdvo_lvds_options(finfo.st_size); + dump_sdvo_panel_dtds(finfo.st_size); + + dump_driver_feature(finfo.st_size); + dump_edp(finfo.st_size); + + return 0; +} diff --git a/tools/intel_disable_clock_gating.c b/tools/intel_disable_clock_gating.c new file mode 100644 index 00000000..8dde3e18 --- /dev/null +++ b/tools/intel_disable_clock_gating.c @@ -0,0 +1,71 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Zhenyu Wang <zhenyuw@linux.intel.com> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <string.h> +#include "intel_gpu_tools.h" + +int main(int argc, char** argv) +{ + struct pci_device *pci_dev; + + pci_dev = intel_get_pci_device(); + intel_get_mmio(pci_dev); + + if (IS_GEN5(pci_dev->device_id)) { + printf("Restore method:\n"); + + printf("intel_reg_write 0x%x 0x%08x\n", + PCH_3DCGDIS0, INREG(PCH_3DCGDIS0)); + OUTREG(PCH_3DCGDIS0, 0xffffffff); + + printf("intel_reg_write 0x%x 0x%08x\n", + PCH_3DCGDIS1, INREG(PCH_3DCGDIS1)); + OUTREG(PCH_3DCGDIS1, 0xffffffff); + + printf("intel_reg_write 0x%x 0x%08x\n", + PCH_3DRAMCGDIS0, INREG(PCH_3DRAMCGDIS0)); + OUTREG(PCH_3DRAMCGDIS0, 0xffffffff); + + printf("intel_reg_write 0x%x 0x%08x\n", + PCH_DSPCLK_GATE_D, INREG(PCH_DSPCLK_GATE_D)); + OUTREG(PCH_DSPCLK_GATE_D, 0xffffffff); + + printf("intel_reg_write 0x%x 0x%08x\n", + PCH_DSPRAMCLK_GATE_D, INREG(PCH_DSPRAMCLK_GATE_D)); + OUTREG(PCH_DSPRAMCLK_GATE_D, 0xffffffff); + } else { + fprintf(stderr, "unsupported chipset\n"); + } + + + return 0; +} + diff --git a/tools/intel_dpio_read.c b/tools/intel_dpio_read.c new file mode 100644 index 00000000..c0c904a6 --- /dev/null +++ b/tools/intel_dpio_read.c @@ -0,0 +1,68 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Vijay Purushothaman <vijay.a.purushothaman@intel.com> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <string.h> +#include "intel_gpu_tools.h" + +static void usage(char *cmdname) +{ + printf("Warning : This program will work only on Valleyview\n"); + printf("Usage: %s [addr]\n", cmdname); + printf("\t addr : in 0xXXXX format\n"); +} + +int main(int argc, char** argv) +{ + int ret = 0; + uint32_t reg, val; + char *cmdname = strdup(argv[0]); + struct pci_device *dev = intel_get_pci_device(); + + if (argc != 2 || !IS_VALLEYVIEW(dev->device_id)) { + usage(cmdname); + ret = 1; + goto out; + } + + sscanf(argv[1], "0x%x", ®); + + intel_register_access_init(dev, 0); + + val = intel_dpio_reg_read(reg); + + printf("Read DPIO register: 0x%x - Value : 0x%x\n", reg, val); + + intel_register_access_fini(); + +out: + free(cmdname); + return ret; +} diff --git a/tools/intel_dpio_write.c b/tools/intel_dpio_write.c new file mode 100644 index 00000000..f8429990 --- /dev/null +++ b/tools/intel_dpio_write.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Vijay Purushothaman <vijay.a.purushothaman@intel.com> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <string.h> +#include "intel_gpu_tools.h" + +static void usage(char *cmdname) +{ + printf("Warning : This program will work only on Valleyview\n"); + printf("Usage: %s [addr] [val]\n", cmdname); + printf("\t addr : in 0xXXXX format\n"); +} + +int main(int argc, char** argv) +{ + int ret = 0; + uint32_t reg, val; + char *cmdname = strdup(argv[0]); + struct pci_device *dev = intel_get_pci_device(); + + if (argc != 3 || !IS_VALLEYVIEW(dev->device_id)) { + usage(cmdname); + ret = 1; + goto out; + } + + sscanf(argv[1], "0x%x", ®); + sscanf(argv[2], "0x%x", &val); + + intel_register_access_init(dev, 0); + + intel_dpio_reg_write(reg, val); + + intel_register_access_fini(); + +out: + free(cmdname); + return ret; +} diff --git a/tools/intel_dump_decode.c b/tools/intel_dump_decode.c new file mode 100644 index 00000000..a3cd2e59 --- /dev/null +++ b/tools/intel_dump_decode.c @@ -0,0 +1,211 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#define _GNU_SOURCE +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <getopt.h> + +#include <intel_bufmgr.h> + +struct drm_intel_decode *ctx; + +static void +read_bin_file(const char * filename) +{ + uint32_t buf[16384]; + int fd, offset, ret; + + if (!strcmp(filename, "-")) + fd = fileno(stdin); + else + fd = open (filename, O_RDONLY); + if (fd < 0) { + fprintf (stderr, "Failed to open %s: %s\n", + filename, strerror (errno)); + exit (1); + } + + drm_intel_decode_set_dump_past_end(ctx, 1); + + offset = 0; + while ((ret = read (fd, buf, sizeof(buf))) > 0) { + drm_intel_decode_set_batch_pointer(ctx, buf, offset, ret/4); + drm_intel_decode(ctx); + offset += ret; + } + close (fd); +} + +static void +read_data_file(const char * filename) +{ + FILE *file; + uint32_t *data = NULL; + int data_size = 0, count = 0, line_number = 0, matched; + char *line = NULL; + size_t line_size; + uint32_t offset, value; + uint32_t gtt_offset = 0; + + if (!strcmp(filename, "-")) + file = stdin; + else + file = fopen (filename, "r"); + + if (file == NULL) { + fprintf (stderr, "Failed to open %s: %s\n", + filename, strerror (errno)); + exit (1); + } + + while (getline (&line, &line_size, file) > 0) { + line_number++; + + matched = sscanf (line, "%08x : %08x", &offset, &value); + if (matched != 2) { + printf("ignoring line %s", line); + + continue; + } + + count++; + + if (count > data_size) { + data_size = data_size ? data_size * 2 : 1024; + data = realloc (data, data_size * sizeof (uint32_t)); + if (data == NULL) { + fprintf (stderr, "Out of memory.\n"); + exit (1); + } + } + + data[count-1] = value; + } + + if (count) { + drm_intel_decode_set_batch_pointer(ctx, data, gtt_offset, count); + drm_intel_decode(ctx); + } + + free (data); + free (line); + + fclose (file); +} + +static void +read_autodetect_file(const char * filename) +{ + int binary = 0, c; + FILE *file; + + file = fopen (filename, "r"); + if (file == NULL) { + fprintf (stderr, "Failed to open %s: %s\n", + filename, strerror (errno)); + exit (1); + } + + while ((c = fgetc(file)) != EOF) { + /* totally lazy binary detector */ + if (c < 10) { + binary = 1; + break; + } + } + + fclose(file); + + if (binary == 1) + read_bin_file(filename); + else + read_data_file(filename); + +} + + +int +main (int argc, char *argv[]) +{ + uint32_t devid = 0xa011; + int i, c; + int option_index = 0; + int binary = -1; + + static struct option long_options[] = { + {"devid", 1, 0, 'd'}, + {"ascii", 0, 0, 'a'}, + {"binary", 0, 0, 'b'} + }; + + while((c = getopt_long(argc, argv, "ab", + long_options, &option_index)) != -1) { + switch(c) { + case 'd': + devid = strtoul(optarg, NULL, 0); + break; + case 'b': + binary = 1; + break; + case 'a': + binary = 0; + break; + default: + printf("unkown command options\n"); + break; + } + } + + ctx = drm_intel_decode_context_alloc(devid); + + if (optind == argc) { + fprintf(stderr, "no input file given\n"); + exit(-1); + } + + for (i = optind; i < argc; i++) { + /* For stdin input, let's read as data file */ + if (!strcmp(argv[i], "-")) { + read_data_file(argv[i]); + continue; + } + if (binary == 1) + read_bin_file(argv[i]); + else if (binary == 0) + read_data_file(argv[i]); + else + read_autodetect_file(argv[i]); + } + + return 0; +} diff --git a/tools/intel_error_decode.c b/tools/intel_error_decode.c new file mode 100644 index 00000000..e0ec8f60 --- /dev/null +++ b/tools/intel_error_decode.c @@ -0,0 +1,515 @@ +/* -*- c-basic-offset: 4 -*- */ +/* + * Copyright © 2007 Intel Corporation + * Copyright © 2009 Intel Corporation + * Copyright © 2010 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Carl Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** @file intel_decode.c + * This file contains code to print out batchbuffer contents in a + * human-readable format. + * + * The current version only supports i915 packets, and only pretty-prints a + * subset of them. The intention is for it to make just a best attempt to + * decode, but never crash in the process. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <err.h> +#include <intel_bufmgr.h> + +#include "intel_chipset.h" +#include "intel_gpu_tools.h" +#include "instdone.h" + +static void +print_instdone (uint32_t devid, unsigned int instdone, unsigned int instdone1) +{ + int i; + static int once; + + if (!once) { + init_instdone_definitions(devid); + once = 1; + } + + for (i = 0; i < num_instdone_bits; i++) { + int busy = 0; + + if (instdone_bits[i].reg == INST_DONE_1) { + if (!(instdone1 & instdone_bits[i].bit)) + busy = 1; + } else { + if (!(instdone & instdone_bits[i].bit)) + busy = 1; + } + + if (busy) + printf(" busy: %s\n", instdone_bits[i].name); + } +} + +static void +print_i830_pgtbl_err(unsigned int reg) +{ + const char *str; + + switch((reg >> 3) & 0xf) { + case 0x1: str = "Overlay TLB"; break; + case 0x2: str = "Display A TLB"; break; + case 0x3: str = "Host TLB"; break; + case 0x4: str = "Render TLB"; break; + case 0x5: str = "Display C TLB"; break; + case 0x6: str = "Mapping TLB"; break; + case 0x7: str = "Command Stream TLB"; break; + case 0x8: str = "Vertex Buffer TLB"; break; + case 0x9: str = "Display B TLB"; break; + case 0xa: str = "Reserved System Memory"; break; + case 0xb: str = "Compressor TLB"; break; + case 0xc: str = "Binner TLB"; break; + default: str = "unknown"; break; + } + + if (str) + printf (" source = %s\n", str); + + switch(reg & 0x7) { + case 0x0: str = "Invalid GTT"; break; + case 0x1: str = "Invalid GTT PTE"; break; + case 0x2: str = "Invalid Memory"; break; + case 0x3: str = "Invalid TLB miss"; break; + case 0x4: str = "Invalid PTE data"; break; + case 0x5: str = "Invalid LocalMemory not present"; break; + case 0x6: str = "Invalid Tiling"; break; + case 0x7: str = "Host to CAM"; break; + } + printf (" error = %s\n", str); +} + +static void +print_i915_pgtbl_err(unsigned int reg) +{ + if (reg & (1 << 29)) + printf (" Cursor A: Invalid GTT PTE\n"); + if (reg & (1 << 28)) + printf (" Cursor B: Invalid GTT PTE\n"); + if (reg & (1 << 27)) + printf (" MT: Invalid tiling\n"); + if (reg & (1 << 26)) + printf (" MT: Invalid GTT PTE\n"); + if (reg & (1 << 25)) + printf (" LC: Invalid tiling\n"); + if (reg & (1 << 24)) + printf (" LC: Invalid GTT PTE\n"); + if (reg & (1 << 23)) + printf (" BIN VertexData: Invalid GTT PTE\n"); + if (reg & (1 << 22)) + printf (" BIN Instruction: Invalid GTT PTE\n"); + if (reg & (1 << 21)) + printf (" CS VertexData: Invalid GTT PTE\n"); + if (reg & (1 << 20)) + printf (" CS Instruction: Invalid GTT PTE\n"); + if (reg & (1 << 19)) + printf (" CS: Invalid GTT\n"); + if (reg & (1 << 18)) + printf (" Overlay: Invalid tiling\n"); + if (reg & (1 << 16)) + printf (" Overlay: Invalid GTT PTE\n"); + if (reg & (1 << 14)) + printf (" Display C: Invalid tiling\n"); + if (reg & (1 << 12)) + printf (" Display C: Invalid GTT PTE\n"); + if (reg & (1 << 10)) + printf (" Display B: Invalid tiling\n"); + if (reg & (1 << 8)) + printf (" Display B: Invalid GTT PTE\n"); + if (reg & (1 << 6)) + printf (" Display A: Invalid tiling\n"); + if (reg & (1 << 4)) + printf (" Display A: Invalid GTT PTE\n"); + if (reg & (1 << 1)) + printf (" Host Invalid PTE data\n"); + if (reg & (1 << 0)) + printf (" Host Invalid GTT PTE\n"); +} + +static void +print_i965_pgtbl_err(unsigned int reg) +{ + if (reg & (1 << 26)) + printf (" Invalid Sampler Cache GTT entry\n"); + if (reg & (1 << 24)) + printf (" Invalid Render Cache GTT entry\n"); + if (reg & (1 << 23)) + printf (" Invalid Instruction/State Cache GTT entry\n"); + if (reg & (1 << 22)) + printf (" There is no ROC, this cannot occur!\n"); + if (reg & (1 << 21)) + printf (" Invalid GTT entry during Vertex Fetch\n"); + if (reg & (1 << 20)) + printf (" Invalid GTT entry during Command Fetch\n"); + if (reg & (1 << 19)) + printf (" Invalid GTT entry during CS\n"); + if (reg & (1 << 18)) + printf (" Invalid GTT entry during Cursor Fetch\n"); + if (reg & (1 << 17)) + printf (" Invalid GTT entry during Overlay Fetch\n"); + if (reg & (1 << 8)) + printf (" Invalid GTT entry during Display B Fetch\n"); + if (reg & (1 << 4)) + printf (" Invalid GTT entry during Display A Fetch\n"); + if (reg & (1 << 1)) + printf (" Valid PTE references illegal memory\n"); + if (reg & (1 << 0)) + printf (" Invalid GTT entry during fetch for host\n"); +} + +static void +print_pgtbl_err(unsigned int reg, unsigned int devid) +{ + if (IS_965(devid)) { + return print_i965_pgtbl_err(reg); + } else if (IS_GEN3(devid)) { + return print_i915_pgtbl_err(reg); + } else { + return print_i830_pgtbl_err(reg); + } +} + +static void +print_snb_fence(unsigned int devid, uint64_t fence) +{ + printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n", + fence & 1 ? "" : "in", + fence & (1<<1) ? 'y' : 'x', + (int)(((fence>>32)&0xfff)+1)*128, + (uint32_t)fence & 0xfffff000, + (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096)); +} + +static void +print_i965_fence(unsigned int devid, uint64_t fence) +{ + printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n", + fence & 1 ? "" : "in", + fence & (1<<1) ? 'y' : 'x', + (int)(((fence>>2)&0x1ff)+1)*128, + (uint32_t)fence & 0xfffff000, + (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096)); +} + +static void +print_i915_fence(unsigned int devid, uint64_t fence) +{ + unsigned tile_width; + if ((fence & 12) && !IS_915(devid)) + tile_width = 128; + else + tile_width = 512; + + printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %i\n", + fence & 1 ? "" : "in", + fence & 12 ? 'y' : 'x', + (1<<((fence>>4)&0xf))*tile_width, + (uint32_t)fence & 0xff00000, + 1<<(20 + ((fence>>8)&0xf))); +} + +static void +print_i830_fence(unsigned int devid, uint64_t fence) +{ + printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %i\n", + fence & 1 ? "" : "in", + fence & 12 ? 'y' : 'x', + (1<<((fence>>4)&0xf))*128, + (uint32_t)fence & 0x7f80000, + 1<<(19 + ((fence>>8)&0xf))); +} + +static void +print_fence(unsigned int devid, uint64_t fence) +{ + if (IS_GEN6(devid) || IS_GEN7(devid)) { + return print_snb_fence(devid, fence); + } else if (IS_GEN4(devid) || IS_GEN5(devid)) { + return print_i965_fence(devid, fence); + } else if (IS_GEN3(devid)) { + return print_i915_fence(devid, fence); + } else { + return print_i830_fence(devid, fence); + } +} + +static void +read_data_file (FILE *file) +{ + struct drm_intel_decode *decode_ctx = NULL; + uint32_t devid = PCI_CHIP_I855_GM; + uint32_t *data = NULL; + long long unsigned fence; + int data_size = 0, count = 0, line_number = 0, matched; + char *line = NULL; + size_t line_size; + uint32_t offset, value; + uint32_t gtt_offset = 0, new_gtt_offset; + const char *buffer_type[2] = { "ringbuffer", "batchbuffer" }; + char *ring_name = NULL; + int is_batch = 1; + + while (getline (&line, &line_size, file) > 0) { + char *dashes; + line_number++; + + dashes = strstr(line, "---"); + if (dashes) { + char *new_ring_name = malloc(dashes - line); + strncpy(new_ring_name, line, dashes - line); + new_ring_name[dashes - line - 1] = '\0'; + + matched = sscanf (dashes, "--- gtt_offset = 0x%08x\n", + &new_gtt_offset); + if (matched == 1) { + if (count) { + printf("%s (%s) at 0x%08x:\n", + buffer_type[is_batch], + ring_name, + gtt_offset); + drm_intel_decode_set_batch_pointer(decode_ctx, + data, gtt_offset, + count); + drm_intel_decode(decode_ctx); + count = 0; + } + gtt_offset = new_gtt_offset; + is_batch = 1; + free(ring_name); + ring_name = new_ring_name; + continue; + } + + matched = sscanf (dashes, "--- ringbuffer = 0x%08x\n", + &new_gtt_offset); + if (matched == 1) { + if (count) { + printf("%s (%s) at 0x%08x:\n", + buffer_type[is_batch], + ring_name, + gtt_offset); + drm_intel_decode_set_batch_pointer(decode_ctx, + data, gtt_offset, + count); + drm_intel_decode(decode_ctx); + count = 0; + } + gtt_offset = new_gtt_offset; + is_batch = 0; + free(ring_name); + ring_name = new_ring_name; + continue; + } + } + + matched = sscanf (line, "%08x : %08x", &offset, &value); + if (matched != 2) { + unsigned int reg; + + /* display reg section is after the ringbuffers, don't mix them */ + if (count) { + printf("%s (%s) at 0x%08x:\n", + buffer_type[is_batch], + ring_name, + gtt_offset); + drm_intel_decode_set_batch_pointer(decode_ctx, + data, gtt_offset, + count); + drm_intel_decode(decode_ctx); + count = 0; + } + + printf("%s", line); + + matched = sscanf (line, "PCI ID: 0x%04x\n", ®); + if (matched == 0) + matched = sscanf (line, " PCI ID: 0x%04x\n", ®); + if (matched == 1) { + devid = reg; + printf("Detected GEN%i chipset\n", + intel_gen(devid)); + + decode_ctx = drm_intel_decode_context_alloc(devid); + } + + matched = sscanf (line, " ACTHD: 0x%08x\n", ®); + if (matched == 1) + drm_intel_decode_set_head_tail(decode_ctx, reg, 0xffffffff); + + matched = sscanf (line, " PGTBL_ER: 0x%08x\n", ®); + if (matched == 1 && reg) + print_pgtbl_err(reg, devid); + + matched = sscanf (line, " INSTDONE: 0x%08x\n", ®); + if (matched == 1) + print_instdone (devid, reg, -1); + + matched = sscanf (line, " INSTDONE1: 0x%08x\n", ®); + if (matched == 1) + print_instdone (devid, -1, reg); + + matched = sscanf (line, " fence[%i] = %Lx\n", ®, &fence); + if (matched == 2) + print_fence (devid, fence); + + continue; + } + + count++; + + if (count > data_size) { + data_size = data_size ? data_size * 2 : 1024; + data = realloc (data, data_size * sizeof (uint32_t)); + if (data == NULL) { + fprintf (stderr, "Out of memory.\n"); + exit (1); + } + } + + data[count-1] = value; + } + + if (count) { + printf("%s (%s) at 0x%08x:\n", + buffer_type[is_batch], + ring_name, + gtt_offset); + drm_intel_decode_set_batch_pointer(decode_ctx, + data, gtt_offset, + count); + drm_intel_decode(decode_ctx); + } + + free (data); + free (line); + free (ring_name); +} + +int +main (int argc, char *argv[]) +{ + FILE *file; + const char *path; + char *filename = NULL; + struct stat st; + int error; + + if (argc > 2) { + fprintf (stderr, + "intel_gpu_decode: Parse an Intel GPU i915_error_state\n" + "Usage:\n" + "\t%s [<file>]\n" + "\n" + "With no arguments, debugfs-dri-directory is probed for in " + "/debug and \n" + "/sys/kernel/debug. Otherwise, it may be " + "specified. If a file is given,\n" + "it is parsed as an GPU dump in the format of " + "/debug/dri/0/i915_error_state.\n", + argv[0]); + return 1; + } + + if (argc == 1) { + if (isatty(0)) { + path = "/debug/dri"; + error = stat (path, &st); + if (error != 0) { + path = "/sys/kernel/debug/dri"; + error = stat (path, &st); + if (error != 0) { + errx(1, + "Couldn't find i915 debugfs directory.\n\n" + "Is debugfs mounted? You might try mounting it with a command such as:\n\n" + "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n"); + } + } + } else { + read_data_file(stdin); + exit(0); + } + } else { + path = argv[1]; + error = stat (path, &st); + if (error != 0) { + fprintf (stderr, "Error opening %s: %s\n", + path, strerror (errno)); + exit (1); + } + } + + if (S_ISDIR (st.st_mode)) { + asprintf (&filename, "%s/i915_error_state", path); + file = fopen(filename, "r"); + if (!file) { + int minor; + for (minor = 0; minor < 64; minor++) { + free(filename); + asprintf(&filename, "%s/%d/i915_error_state", path, minor); + file = fopen(filename, "r"); + if (file) + break; + } + } + if (!file) { + fprintf (stderr, "Failed to find i915_error_state beneath %s\n", + path); + exit (1); + } + } else { + file = fopen(path, "r"); + if (!file) { + fprintf (stderr, "Failed to open %s: %s\n", + path, strerror (errno)); + exit (1); + } + } + + read_data_file (file); + fclose (file); + + if (filename != path) + free (filename); + + return 0; +} diff --git a/tools/intel_forcewaked.c b/tools/intel_forcewaked.c new file mode 100644 index 00000000..3ab2d6f8 --- /dev/null +++ b/tools/intel_forcewaked.c @@ -0,0 +1,106 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#include <assert.h> +#include <err.h> +#include <string.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <unistd.h> +#include "intel_gpu_tools.h" + +bool daemonized; + +#define INFO_PRINT(...) \ + do { \ + if (daemonized) \ + syslog(LOG_INFO, ##__VA_ARGS__); \ + else \ + fprintf(stdout, ##__VA_ARGS__); \ + } while(0) + +static void +help(char *prog) { + printf("%s Prevents the GT from sleeping.\n\n", prog); + printf("usage: %s [options] \n\n", prog); + printf("Options: \n"); + printf(" -b Run in background/daemon mode\n"); +} + +static int +is_alive(void) { + /* Read the timestamp, which should *almost* always be !0 */ + return (intel_register_read(0x2358) != 0); +} + +int main(int argc, char *argv[]) +{ + int ret; + + if (argc > 2 || (argc == 2 && !strncmp(argv[1], "-h", 2))) { + help(argv[1]); + exit(0); + } + + if (argc == 2 && (!strncmp(argv[1], "-b", 2))) + daemonized = true; + + if (daemonized) { + assert(daemon(0, 0) == 0); + openlog(argv[0], LOG_CONS | LOG_PID, LOG_USER); + INFO_PRINT("started daemon"); + } + + ret = intel_register_access_init(intel_get_pci_device(), 1); + if (ret) { + INFO_PRINT("Couldn't init register access\n"); + exit(1); + } else { + INFO_PRINT("Forcewake locked\n"); + } + while(1) { + if (!is_alive()) { + INFO_PRINT("gpu reset? restarting daemon\n"); + intel_register_access_fini(); + ret = intel_register_access_init(intel_get_pci_device(), + 1); + } + sleep(1); + } + intel_register_access_fini(); + INFO_PRINT("Forcewake unlock\n"); + + if (daemonized) { + INFO_PRINT("finished\n"); + closelog(); + } + + return 0; +} diff --git a/tools/intel_gpu_abrt b/tools/intel_gpu_abrt new file mode 100755 index 00000000..141a5246 --- /dev/null +++ b/tools/intel_gpu_abrt @@ -0,0 +1,45 @@ +#!/bin/sh + +if [ -d /debug/dri ] ; then + debugfs_path=/debug_dri +fi + +if [ -d /sys/kernel/debug/dri ] ; then + debugfs_path=/sys/kernel/debug/dri +fi + +i915_debugfs=x +for dir in `ls $debugfs_path` ; do + if [ -f $debugfs_path/$dir/i915_error_state ] ; then + i915_debugfs=$debugfs_path/$dir + break + fi +done + +if [ $i915_debugfs = "x" ] ; then + echo i915 debugfs path not found. + exit 1 +fi + +tmpdir=`mktemp -d` +tardir=$tmpdir/intel_gpu_abrt +mkdir $tardir + +mkdir $tardir/debugfs +cp $i915_debugfs/* $tardir/debugfs + +mkdir $tardir/mod_opts +cp /sys/module/i915/parameters/* $tardir/mod_opts + +mkdir $tardir/X +cp /var/log/Xorg.*.log $tardir/X +cp /etc/X11/xorg.conf $tardir/X + +dmesg > $tardir/dmesg +lspci -nn > $tardir/lspci + +(cd $tmpdir; tar -c intel_gpu_abrt ) > intel_gpu_abrt.tar + +rm $tmpdir -Rf + +exit 0 diff --git a/tools/intel_gpu_time.c b/tools/intel_gpu_time.c new file mode 100644 index 00000000..c30b84d2 --- /dev/null +++ b/tools/intel_gpu_time.c @@ -0,0 +1,110 @@ +/* + * Copyright © 2007,2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h> + +#include "intel_gpu_tools.h" + +#define SAMPLES_PER_SEC 10000 + +static volatile int goddo; + +static pid_t spawn(char **argv) +{ + pid_t pid; + + pid = fork(); + if (pid != 0) + return pid; + + execvp(argv[0], argv); + exit(1); +} + +static void sighandler(int sig) +{ + goddo = sig; +} + +int main(int argc, char **argv) +{ + pid_t child; + uint64_t ring_idle = 0, ring_time = 0; + struct timeval start, end; + static struct rusage rusage; + int status; + + intel_get_mmio(intel_get_pci_device()); + + if (argc == 1) { + fprintf(stderr, "usage: %s cmd [args...]\n", argv[0]); + return 1; + } + + signal(SIGCHLD, sighandler); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + + gettimeofday(&start, NULL); + child = spawn(argv+1); + if (child < 0) + return 127; + + while (!goddo) { + uint32_t ring_head, ring_tail; + + ring_head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; + ring_tail = INREG(LP_RING + RING_TAIL) & TAIL_ADDR; + + if (ring_tail == ring_head) + ring_idle++; + ring_time++; + + usleep(1000000 / SAMPLES_PER_SEC); + } + gettimeofday(&end, NULL); + timersub(&end, &start, &end); + + waitpid(child, &status, 0); + + getrusage(RUSAGE_CHILDREN, &rusage); + printf("user: %ld.%06lds, sys: %ld.%06lds, elapsed: %ld.%06lds, CPU: %.1f%%, GPU: %.1f%%\n", + rusage.ru_utime.tv_sec, rusage.ru_utime.tv_usec, + rusage.ru_stime.tv_sec, rusage.ru_stime.tv_usec, + end.tv_sec, end.tv_usec, + 100*(rusage.ru_utime.tv_sec + 1e-6*rusage.ru_utime.tv_usec + rusage.ru_stime.tv_sec + 1e-6*rusage.ru_stime.tv_usec) / (end.tv_sec + 1e-6*end.tv_usec), + 100 - ring_idle * 100. / ring_time); + + return WEXITSTATUS(status); +} diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c new file mode 100644 index 00000000..e561865c --- /dev/null +++ b/tools/intel_gpu_top.c @@ -0,0 +1,716 @@ +/* + * Copyright © 2007 Intel Corporation + * Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Eugeni Dodonov <eugeni.dodonov@intel.com> + * + */ + +#include "config.h" + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <string.h> +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#endif +#include "intel_gpu_tools.h" +#include "instdone.h" + +#define FORCEWAKE 0xA18C +#define FORCEWAKE_ACK 0x130090 + +#define SAMPLES_PER_SEC 10000 +#define SAMPLES_TO_PERCENT_RATIO (SAMPLES_PER_SEC / 100) + +#define MAX_NUM_TOP_BITS 100 + +#define HAS_STATS_REGS(devid) IS_965(devid) + +struct top_bit { + struct instdone_bit *bit; + int count; +} top_bits[MAX_NUM_TOP_BITS]; +struct top_bit *top_bits_sorted[MAX_NUM_TOP_BITS]; + +static uint32_t instdone, instdone1; + +static const char *bars[] = { + " ", + "▏", + "▎", + "▍", + "▌", + "▋", + "▊", + "▉", + "█" +}; + +enum stats_counts { + IA_VERTICES, + IA_PRIMITIVES, + VS_INVOCATION, + GS_INVOCATION, + GS_PRIMITIVES, + CL_INVOCATION, + CL_PRIMITIVES, + PS_INVOCATION, + PS_DEPTH, + STATS_COUNT +}; + +const uint32_t stats_regs[STATS_COUNT] = { + IA_VERTICES_COUNT_QW, + IA_PRIMITIVES_COUNT_QW, + VS_INVOCATION_COUNT_QW, + GS_INVOCATION_COUNT_QW, + GS_PRIMITIVES_COUNT_QW, + CL_INVOCATION_COUNT_QW, + CL_PRIMITIVES_COUNT_QW, + PS_INVOCATION_COUNT_QW, + PS_DEPTH_COUNT_QW, +}; + +const char *stats_reg_names[STATS_COUNT] = { + "vert fetch", + "prim fetch", + "VS invocations", + "GS invocations", + "GS prims", + "CL invocations", + "CL prims", + "PS invocations", + "PS depth pass", +}; + +uint64_t stats[STATS_COUNT]; +uint64_t last_stats[STATS_COUNT]; + +static unsigned long +gettime(void) +{ + struct timeval t; + gettimeofday(&t, NULL); + return (t.tv_usec + (t.tv_sec * 1000000)); +} + +static int +top_bits_sort(const void *a, const void *b) +{ + struct top_bit * const *bit_a = a; + struct top_bit * const *bit_b = b; + int a_count = (*bit_a)->count; + int b_count = (*bit_b)->count; + + if (a_count < b_count) + return 1; + else if (a_count == b_count) + return 0; + else + return -1; +} + +static void +update_idle_bit(struct top_bit *top_bit) +{ + uint32_t reg_val; + + if (top_bit->bit->reg == INST_DONE_1) + reg_val = instdone1; + else + reg_val = instdone; + + if ((reg_val & top_bit->bit->bit) == 0) + top_bit->count++; +} + +static void +print_clock(const char *name, int clock) { + if (clock == -1) + printf("%s clock: unknown", name); + else + printf("%s clock: %d Mhz", name, clock); +} + +static int +print_clock_info(struct pci_device *pci_dev) +{ + uint32_t devid = pci_dev->device_id; + uint16_t gcfgc; + + if (IS_GM45(devid)) { + int core_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0xf) { + case 8: + core_clock = 266; + break; + case 9: + core_clock = 320; + break; + case 11: + core_clock = 400; + break; + case 13: + core_clock = 533; + break; + } + print_clock("core", core_clock); + } else if (IS_965(devid) && IS_MOBILE(devid)) { + int render_clock = -1, sampler_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0xf) { + case 2: + render_clock = 250; sampler_clock = 267; + break; + case 3: + render_clock = 320; sampler_clock = 333; + break; + case 4: + render_clock = 400; sampler_clock = 444; + break; + case 5: + render_clock = 500; sampler_clock = 533; + break; + } + + print_clock("render", render_clock); + printf(" "); + print_clock("sampler", sampler_clock); + } else if (IS_945(devid) && IS_MOBILE(devid)) { + int render_clock = -1, display_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0x7) { + case 0: + render_clock = 166; + break; + case 1: + render_clock = 200; + break; + case 3: + render_clock = 250; + break; + case 5: + render_clock = 400; + break; + } + + switch (gcfgc & 0x70) { + case 0: + display_clock = 200; + break; + case 4: + display_clock = 320; + break; + } + if (gcfgc & (1 << 7)) + display_clock = 133; + + print_clock("render", render_clock); + printf(" "); + print_clock("display", display_clock); + } else if (IS_915(devid) && IS_MOBILE(devid)) { + int render_clock = -1, display_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0x7) { + case 0: + render_clock = 160; + break; + case 1: + render_clock = 190; + break; + case 4: + render_clock = 333; + break; + } + if (gcfgc & (1 << 13)) + render_clock = 133; + + switch (gcfgc & 0x70) { + case 0: + display_clock = 190; + break; + case 4: + display_clock = 333; + break; + } + if (gcfgc & (1 << 7)) + display_clock = 133; + + print_clock("render", render_clock); + printf(" "); + print_clock("display", display_clock); + } + + + printf("\n"); + return -1; +} + +#define STATS_LEN (20) +#define PERCENTAGE_BAR_END (79 - STATS_LEN) + +static void +print_percentage_bar(float percent, int cur_line_len) +{ + int bar_avail_len = (PERCENTAGE_BAR_END - cur_line_len - 1) * 8; + int bar_len = bar_avail_len * (percent + .5) / 100.0; + int i; + + for (i = bar_len; i >= 8; i -= 8) { + printf("%s", bars[8]); + cur_line_len++; + } + if (i) { + printf("%s", bars[i]); + cur_line_len++; + } + + /* NB: We can't use a field width with utf8 so we manually + * guarantee a field with of 45 chars for any bar. */ + printf("%*s", PERCENTAGE_BAR_END - cur_line_len, ""); +} + +struct ring { + const char *name; + uint32_t mmio; + int head, tail, size; + uint64_t full; + int idle; +}; + +static uint32_t ring_read(struct ring *ring, uint32_t reg) +{ + return INREG(ring->mmio + reg); +} + +static void ring_init(struct ring *ring) +{ + ring->size = (((ring_read(ring, RING_LEN) & RING_NR_PAGES) >> 12) + 1) * 4096; +} + +static void ring_reset(struct ring *ring) +{ + ring->idle = ring->full = 0; +} + +static void ring_sample(struct ring *ring) +{ + int full; + + if (!ring->size) + return; + + ring->head = ring_read(ring, RING_HEAD) & HEAD_ADDR; + ring->tail = ring_read(ring, RING_TAIL) & TAIL_ADDR; + + if (ring->tail == ring->head) + ring->idle++; + + full = ring->tail - ring->head; + if (full < 0) + full += ring->size; + ring->full += full; +} + +static void ring_print_header(FILE *out, struct ring *ring) +{ + fprintf(out, "%.6s%%\tops\t", + ring->name + ); +} + +static void ring_print(struct ring *ring, unsigned long samples_per_sec) +{ + int percent_busy, len; + + if (!ring->size) + return; + + percent_busy = 100 - 100 * ring->idle / samples_per_sec; + + len = printf("%25s busy: %3d%%: ", ring->name, percent_busy); + print_percentage_bar (percent_busy, len); + printf("%24s space: %d/%d\n", + ring->name, + (int)(ring->full / samples_per_sec), + ring->size); +} + +static void ring_log(struct ring *ring, unsigned long samples_per_sec, + FILE *output) +{ + if (ring->size) + fprintf(output, "%3d\t%d\t", + (int)(100 - 100 * ring->idle / samples_per_sec), + (int)(ring->full / samples_per_sec)); + else + fprintf(output, "-1\t-1\t"); +} + +static void +usage(const char *appname) +{ + printf("intel_gpu_top - Display a top-like summary of Intel GPU usage\n" + "\n" + "usage: %s [parameters]\n" + "\n" + "The following parameters apply:\n" + "[-s <samples>] samples per seconds (default %d)\n" + "[-e <command>] command to profile\n" + "[-o <file>] output statistics to file. If file is '-'," + " run in batch mode and output statistics to stdio only \n" + "[-h] show this help screen\n" + "\n", + appname, + SAMPLES_PER_SEC + ); + return; +} + +int main(int argc, char **argv) +{ + uint32_t devid; + struct pci_device *pci_dev; + struct ring render_ring = { + .name = "render", + .mmio = 0x2030, + }, bsd_ring = { + .name = "bitstream", + .mmio = 0x4030, + }, bsd6_ring = { + .name = "bitstream", + .mmio = 0x12030, + }, blt_ring = { + .name = "blitter", + .mmio = 0x22030, + }; + int i, ch; + int samples_per_sec = SAMPLES_PER_SEC; + FILE *output = NULL; + double elapsed_time=0; + int print_headers=1; + pid_t child_pid=-1; + int child_stat; + char *cmd=NULL; + int interactive=1; + + /* Parse options? */ + while ((ch = getopt(argc, argv, "s:o:e:h")) != -1) { + switch (ch) { + case 'e': cmd = strdup(optarg); + break; + case 's': samples_per_sec = atoi(optarg); + if (samples_per_sec < 100) { + fprintf(stderr, "Error: samples per second must be >= 100\n"); + exit(1); + } + break; + case 'o': + if (!strcmp(optarg, "-")) { + /* Running in non-interactive mode */ + interactive = 0; + output = stdout; + } + else + output = fopen(optarg, "w"); + if (!output) + { + perror("fopen"); + exit(1); + } + break; + case 'h': + usage(argv[0]); + exit(0); + break; + default: + fprintf(stderr, "Invalid flag %c!\n", (char)optopt); + usage(argv[0]); + exit(1); + break; + } + } + argc -= optind; + argv += optind; + + pci_dev = intel_get_pci_device(); + devid = pci_dev->device_id; + intel_get_mmio(pci_dev); + init_instdone_definitions(devid); + + /* Do we have a command to run? */ + if (cmd != NULL) { + if (output) { + fprintf(output, "# Profiling: %s\n", cmd); + fflush(output); + } + child_pid = fork(); + if (child_pid < 0) { + perror("fork"); + exit(1); + } + else if (child_pid == 0) { + int res; + res = system(cmd); + if (res < 0) + perror("running command"); + if (output) { + fflush(output); + fprintf(output, "# %s exited with status %d\n", cmd, res); + fflush(output); + } + free(cmd); + exit(0); + } else { + free(cmd); + } + } + + for (i = 0; i < num_instdone_bits; i++) { + top_bits[i].bit = &instdone_bits[i]; + top_bits[i].count = 0; + top_bits_sorted[i] = &top_bits[i]; + } + + /* Grab access to the registers */ + intel_register_access_init(pci_dev, 0); + + ring_init(&render_ring); + if (IS_GEN4(devid) || IS_GEN5(devid)) + ring_init(&bsd_ring); + if (IS_GEN6(devid) || IS_GEN7(devid)) { + ring_init(&bsd6_ring); + ring_init(&blt_ring); + } + + /* Initialize GPU stats */ + if (HAS_STATS_REGS(devid)) { + for (i = 0; i < STATS_COUNT; i++) { + uint32_t stats_high, stats_low, stats_high_2; + + do { + stats_high = INREG(stats_regs[i] + 4); + stats_low = INREG(stats_regs[i]); + stats_high_2 = INREG(stats_regs[i] + 4); + } while (stats_high != stats_high_2); + + last_stats[i] = (uint64_t)stats_high << 32 | + stats_low; + } + } + + for (;;) { + int j; + unsigned long long t1, ti, tf, t2; + unsigned long long def_sleep = 1000000 / samples_per_sec; + unsigned long long last_samples_per_sec = samples_per_sec; + unsigned short int max_lines; + struct winsize ws; + char clear_screen[] = {0x1b, '[', 'H', + 0x1b, '[', 'J', + 0x0}; + int percent; + int len; + + t1 = gettime(); + + ring_reset(&render_ring); + ring_reset(&bsd_ring); + ring_reset(&bsd6_ring); + ring_reset(&blt_ring); + + for (i = 0; i < samples_per_sec; i++) { + long long interval; + ti = gettime(); + if (IS_965(devid)) { + instdone = INREG(INST_DONE_I965); + instdone1 = INREG(INST_DONE_1); + } else + instdone = INREG(INST_DONE); + + for (j = 0; j < num_instdone_bits; j++) + update_idle_bit(&top_bits[j]); + + ring_sample(&render_ring); + ring_sample(&bsd_ring); + ring_sample(&bsd6_ring); + ring_sample(&blt_ring); + + tf = gettime(); + if (tf - t1 >= 1000000) { + /* We are out of sync, bail out */ + last_samples_per_sec = i+1; + break; + } + interval = def_sleep - (tf - ti); + if (interval > 0) + usleep(interval); + } + + if (HAS_STATS_REGS(devid)) { + for (i = 0; i < STATS_COUNT; i++) { + uint32_t stats_high, stats_low, stats_high_2; + + do { + stats_high = INREG(stats_regs[i] + 4); + stats_low = INREG(stats_regs[i]); + stats_high_2 = INREG(stats_regs[i] + 4); + } while (stats_high != stats_high_2); + + stats[i] = (uint64_t)stats_high << 32 | + stats_low; + } + } + + qsort(top_bits_sorted, num_instdone_bits, + sizeof(struct top_bit *), top_bits_sort); + + /* Limit the number of lines printed to the terminal height so the + * most important info (at the top) will stay on screen. */ + max_lines = -1; + if (ioctl(0, TIOCGWINSZ, &ws) != -1) + max_lines = ws.ws_row - 6; /* exclude header lines */ + if (max_lines >= num_instdone_bits) + max_lines = num_instdone_bits; + + t2 = gettime(); + elapsed_time += (t2 - t1) / 1000000.0; + + if (interactive) { + printf("%s", clear_screen); + print_clock_info(pci_dev); + + ring_print(&render_ring, last_samples_per_sec); + ring_print(&bsd_ring, last_samples_per_sec); + ring_print(&bsd6_ring, last_samples_per_sec); + ring_print(&blt_ring, last_samples_per_sec); + + printf("\n%30s %s\n", "task", "percent busy"); + for (i = 0; i < max_lines; i++) { + if (top_bits_sorted[i]->count > 0) { + percent = (top_bits_sorted[i]->count * 100) / + last_samples_per_sec; + len = printf("%30s: %3d%%: ", + top_bits_sorted[i]->bit->name, + percent); + print_percentage_bar (percent, len); + } else { + printf("%*s", PERCENTAGE_BAR_END, ""); + } + + if (i < STATS_COUNT && HAS_STATS_REGS(devid)) { + printf("%13s: %llu (%lld/sec)", + stats_reg_names[i], + (long long)stats[i], + (long long)(stats[i] - last_stats[i])); + last_stats[i] = stats[i]; + } else { + if (!top_bits_sorted[i]->count) + break; + } + printf("\n"); + } + } + if (output) { + /* Print headers for columns at first run */ + if (print_headers) { + fprintf(output, "# time\t"); + ring_print_header(output, &render_ring); + ring_print_header(output, &bsd_ring); + ring_print_header(output, &bsd6_ring); + ring_print_header(output, &blt_ring); + for (i = 0; i < MAX_NUM_TOP_BITS; i++) { + if (i < STATS_COUNT && HAS_STATS_REGS(devid)) { + fprintf(output, "%.6s\t", + stats_reg_names[i] + ); + } + if (!top_bits[i].count) + continue; + } + fprintf(output, "\n"); + print_headers = 0; + } + + /* Print statistics */ + fprintf(output, "%.2f\t", elapsed_time); + ring_log(&render_ring, last_samples_per_sec, output); + ring_log(&bsd_ring, last_samples_per_sec, output); + ring_log(&bsd6_ring, last_samples_per_sec, output); + ring_log(&blt_ring, last_samples_per_sec, output); + + for (i = 0; i < MAX_NUM_TOP_BITS; i++) { + if (i < STATS_COUNT && HAS_STATS_REGS(devid)) { + fprintf(output, "%lu\t", + stats[i] - last_stats[i]); + last_stats[i] = stats[i]; + } + if (!top_bits[i].count) + continue; + } + fprintf(output, "\n"); + fflush(output); + } + + for (i = 0; i < num_instdone_bits; i++) { + top_bits_sorted[i]->count = 0; + + if (i < STATS_COUNT) + last_stats[i] = stats[i]; + } + + /* Check if child has gone */ + if (child_pid > 0) { + int res; + if ((res = waitpid(child_pid, &child_stat, WNOHANG)) == -1) { + perror("waitpid"); + exit(1); + } + if (res == 0) + continue; + if (WIFEXITED(child_stat)) + break; + } + } + + fclose(output); + + intel_register_access_fini(); + return 0; +} diff --git a/tools/intel_gtt.c b/tools/intel_gtt.c new file mode 100644 index 00000000..05d36d71 --- /dev/null +++ b/tools/intel_gtt.c @@ -0,0 +1,134 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <pciaccess.h> +#include <unistd.h> + +#include "intel_gpu_tools.h" + +#define INGTT(offset) (*(volatile uint32_t *)(gtt + (offset) / (KB(4) / 4))) + +#define KB(x) ((x) * 1024) +#define MB(x) ((x) * 1024 * 1024) + +int main(int argc, char **argv) +{ + struct pci_device *pci_dev; + int start, aper_size; + unsigned char *gtt; + uint32_t devid; + int flag[] = { + PCI_DEV_MAP_FLAG_WRITE_COMBINE, + PCI_DEV_MAP_FLAG_WRITABLE, + 0 + }, f; + + pci_dev = intel_get_pci_device(); + devid = pci_dev->device_id; + + if (IS_GEN2(devid)) { + printf("Unsupported chipset for gtt dumper\n"); + exit(1); + } + + for (f = 0; flag[f] != 0; f++) { + if (IS_GEN3(devid)) { + /* 915/945 chips has GTT range in bar 3 */ + if (pci_device_map_range(pci_dev, + pci_dev->regions[3].base_addr, + pci_dev->regions[3].size, + flag[f], + (void **)>t) == 0) + break; + } else { + int offset; + if (IS_G4X(devid) || IS_GEN5(devid)) + offset = MB(2); + else + offset = KB(512); + if (pci_device_map_range(pci_dev, + pci_dev->regions[0].base_addr + offset, + offset, + flag[f], + (void **)>t) == 0) + break; + } + } + if (flag[f] == 0) { + printf("Failed to map gtt\n"); + exit(1); + } + + aper_size = pci_dev->regions[2].size; + + for (start = 0; start < aper_size; start += KB(4)) { + uint32_t start_pte = INGTT(start); + uint32_t end; + int constant_length = 0; + int linear_length = 0; + + /* Check if it's a linear sequence */ + for (end = start + KB(4); end < aper_size; end += KB(4)) { + uint32_t end_pte = INGTT(end); + if (end_pte == start_pte + (end - start)) + linear_length++; + else + break; + } + if (linear_length > 0) { + printf("0x%08x - 0x%08x: linear from " + "0x%08x to 0x%08x\n", + start, end - KB(4), + start_pte, start_pte + (end - start) - KB(4)); + start = end - KB(4); + continue; + } + + /* Check if it's a constant sequence */ + for (end = start + KB(4); end < aper_size; end += KB(4)) { + uint32_t end_pte = INGTT(end); + if (end_pte == start_pte) + constant_length++; + else + break; + } + if (constant_length > 0) { + printf("0x%08x - 0x%08x: constant 0x%08x\n", + start, end - KB(4), start_pte); + start = end - KB(4); + continue; + } + + printf("0x%08x: 0x%08x\n", start, start_pte); + } + + return 0; +} diff --git a/tools/intel_infoframes.c b/tools/intel_infoframes.c new file mode 100644 index 00000000..f5a40067 --- /dev/null +++ b/tools/intel_infoframes.c @@ -0,0 +1,1142 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Paulo Zanoni <paulo.r.zanoni@intel.com> + * + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include "intel_gpu_tools.h" + +typedef enum { + TRANSC_A = 0, + TRANSC_B = 1, + TRANSC_C = 2, + TRANSC_INVALID +} Transcoder; + +typedef enum { + REG_HDMIB_GEN4 = 0x61140, + REG_HDMIC_GEN4 = 0x61160, + REG_HDMIB_PCH = 0xe1140, + REG_HDMIC_PCH = 0xe1150, + REG_HDMID_PCH = 0xe1160, + REG_DIP_CTL_GEN4 = 0x61170, + REG_DIP_CTL_A = 0xe0200, + REG_DIP_CTL_B = 0xe1200, + REG_DIP_CTL_C = 0xe2200, + REG_DIP_DATA_GEN4 = 0x61178, + REG_DIP_DATA_A = 0xe0208, + REG_DIP_DATA_B = 0xe1208, + REG_DIP_DATA_C = 0xe2208, +} Register; + +typedef enum { + DIP_AVI = 0, + DIP_VENDOR = 1, + DIP_GAMUT = 2, + DIP_SPD = 3, + DIP_INVALID, +} DipType; + +typedef enum { + DIP_FREQ_ONCE = 0, + DIP_FREQ_EVERY_VSYNC = 1, + DIP_FREQ_EVERY_OTHER_VSYNC = 2, + DIP_FREQ_RESERVED = 3, +} DipFrequency; + +typedef enum { + SOURCE_DEVICE_UNKNOWN = 0x00, + SOURCE_DEVICE_DIGITAL_STB = 0x01, + SOURCE_DEVICE_DVD_PLAYER = 0x02, + SOURCE_DEVICE_D_VHS = 0x03, + SOURCE_DEVICE_HDD_VIDEORECORDER = 0x04, + SOURCE_DEVICE_DVC = 0x05, + SOURCE_DEVICE_DSC = 0x06, + SOURCE_DEVICE_VIDEO_CD = 0x07, + SOURCE_DEVICE_GAME = 0x08, + SOURCE_DEVICE_PC_GENERAL = 0x09, + SOURCE_DEVICE_BLU_RAY_DISK = 0x0a, + SOURCE_DEVICE_SUPER_AUDIO_CD = 0x0b, + SOURCE_DEVICE_RESERVED = 0x0c +} SourceDevice; + +#define HDMI_PORT_ENABLE (1 << 31) +#define HDMI_PORT_TRANSCODER_GEN4 (1 << 30) +#define HDMI_PORT_TRANSCODER_IBX (1 << 30) +#define HDMI_PORT_TRANSCODER_CPT (3 << 29) +#define HDMI_PORT_ENCODING (3 << 10) +#define HDMI_PORT_MODE (1 << 9) +#define HDMI_PORT_AUDIO (1 << 6) +#define HDMI_PORT_DETECTED (1 << 2) + +#define DIP_CTL_ENABLE (1 << 31) +#define DIP_CTL_GCP_ENABLE (1 << 25) +#define DIP_CTL_SPD_ENABLE (1 << 24) +#define DIP_CTL_GAMUT_ENABLE (1 << 23) +#define DIP_CTL_VENDOR_ENABLE (1 << 22) +#define DIP_CTL_AVI_ENABLE (1 << 21) +#define DIP_CTL_BUFFER_INDEX (3 << 19) +#define DIP_CTL_BUFFER_AVI (0 << 19) +#define DIP_CTL_BUFFER_VENDOR (1 << 19) +#define DIP_CTL_BUFFER_GAMUT (2 << 19) +#define DIP_CTL_BUFFER_SPD (3 << 19) +#define DIP_CTL_FREQUENCY (3 << 16) +#define DIP_CTL_FREQ_ONCE (0 << 16) +#define DIP_CTL_FREQ_EVERY (1 << 16) +#define DIP_CTL_FREQ_EVERY_OTHER (2 << 16) +#define DIP_CTL_BUFFER_SIZE (15 << 8) +#define DIP_CTL_ACCESS_ADDR (15 << 0) + +#define DIP_CTL_PORT_SEL_MASK_GEN4 (3 << 29) +#define DIP_CTL_PORT_SEL_B_GEN4 (1 << 29) +#define DIP_CTL_PORT_SEL_C_GEN4 (2 << 29) +#define DIP_CTL_BUFFER_TRANS_ACTIVE_GEN4 (1 << 28) + +#define AVI_INFOFRAME_TYPE 0x82 +#define AVI_INFOFRAME_VERSION 0x02 +#define AVI_INFOFRAME_LENGTH 0x0d +#define SPD_INFOFRAME_TYPE 0x83 +#define SPD_INFOFRAME_VERSION 0x01 +#define SPD_INFOFRAME_LENGTH 0x19 + +typedef struct { + uint8_t type; + uint8_t version; + uint8_t length; + uint8_t ecc; +} DipInfoFrameHeader; + +typedef union { + struct { + DipInfoFrameHeader header; + uint8_t checksum; + + uint8_t S :2; + uint8_t B :2; + uint8_t A :1; + uint8_t Y :2; + uint8_t Rsvd0 :1; + + uint8_t R :4; + uint8_t M :2; + uint8_t C :2; + + uint8_t SC :2; + uint8_t Q :2; + uint8_t EC :3; + uint8_t ITC :1; + + uint8_t VIC :7; + uint8_t Rsvd1 :1; + + uint8_t PR :4; + uint8_t Rsvd2 :4; + + uint16_t top; + uint16_t bottom; + uint16_t left; + uint16_t right; + + uint16_t Rsvd3; + uint32_t Rsvd4[3]; + } avi; + struct { + DipInfoFrameHeader header; + uint8_t checksum; + uint8_t vendor[8]; + uint8_t description[16]; + uint8_t source; + } __attribute__((packed)) spd; + struct { + DipInfoFrameHeader header; + uint8_t body[27]; + } generic; + uint8_t data8[128]; + uint32_t data32[16]; +} DipInfoFrame; + +Register gen4_hdmi_ports[] = { + REG_HDMIB_GEN4, + REG_HDMIC_GEN4, +}; +Register pch_hdmi_ports[] = { + REG_HDMIB_PCH, + REG_HDMIC_PCH, + REG_HDMID_PCH +}; +Register pch_dip_ctl_regs[] = { + REG_DIP_CTL_A, + REG_DIP_CTL_B, + REG_DIP_CTL_C +}; +Register pch_dip_data_regs[] = { + REG_DIP_DATA_A, + REG_DIP_DATA_B, + REG_DIP_DATA_C +}; +const char *hdmi_port_names[] = { + "HDMIB", + "HDMIC", + "HDMID" +}; +const char *transcoder_names[] = { + "A", + "B", + "C" +}; +const char *dip_frequency_names[] = { + "once", + "every vsync", + "every other vsync", + "reserved (invalid)" +}; + +int gen = 0; + +static const char *spd_source_to_string(SourceDevice source) +{ + switch (source) { + case SOURCE_DEVICE_UNKNOWN: + return "unknown"; + case SOURCE_DEVICE_DIGITAL_STB: + return "digital stb"; + case SOURCE_DEVICE_DVD_PLAYER: + return "dvd player"; + case SOURCE_DEVICE_D_VHS: + return "d vhs"; + case SOURCE_DEVICE_HDD_VIDEORECORDER: + return "hdd videorecorder"; + case SOURCE_DEVICE_DVC: + return "dvc"; + case SOURCE_DEVICE_DSC: + return "dsc"; + case SOURCE_DEVICE_VIDEO_CD: + return "video cd"; + case SOURCE_DEVICE_GAME: + return "game"; + case SOURCE_DEVICE_PC_GENERAL: + return "pc general"; + case SOURCE_DEVICE_BLU_RAY_DISK: + return "blu-ray disk"; + case SOURCE_DEVICE_SUPER_AUDIO_CD: + return "super audio cd"; + default: + return "reserved"; + } +} + +static Register get_dip_ctl_reg(Transcoder transcoder) +{ + if (gen == 4) + return REG_DIP_CTL_GEN4; + else + return pch_dip_ctl_regs[transcoder]; +} + +static Register get_dip_data_reg(Transcoder transcoder) +{ + if (gen == 4) + return REG_DIP_DATA_GEN4; + else + return pch_dip_data_regs[transcoder]; +} + +static Register get_hdmi_port(int hdmi_port_index) +{ + if (gen == 4) { + assert(hdmi_port_index < 2); + return gen4_hdmi_ports[hdmi_port_index]; + } else { + return pch_hdmi_ports[hdmi_port_index]; + } +} + +static void load_infoframe(Transcoder transcoder, DipInfoFrame *frame, + DipType type) +{ + Register ctl_reg = get_dip_ctl_reg(transcoder); + Register data_reg = get_dip_data_reg(transcoder); + uint32_t ctl_val; + uint32_t i; + + ctl_val = INREG(ctl_reg); + + ctl_val &= ~DIP_CTL_BUFFER_INDEX; + ctl_val |= type << 19; + OUTREG(ctl_reg, ctl_val); + ctl_val = INREG(ctl_reg); + + ctl_val &= ~DIP_CTL_ACCESS_ADDR; + OUTREG(ctl_reg, ctl_val); + + for (i = 0; i < 16; i++) { + ctl_val = INREG(ctl_reg); + assert((ctl_val & DIP_CTL_ACCESS_ADDR) == i); + frame->data32[i] = INREG(data_reg); + } +} + +static int infoframe_valid_checksum(DipInfoFrame *frame) +{ + int i; + int length = frame->generic.header.length; + uint8_t csum; + + csum = frame->generic.header.type + frame->generic.header.version + + frame->generic.header.length; /* no ecc */ + for (i = 0; i < length + 1; i++) + csum += frame->generic.body[i]; + + return (csum == 0); +} + +static void infoframe_fix_checksum(DipInfoFrame *frame) +{ + int i; + int length = frame->generic.header.length; + uint8_t csum; + + csum = frame->generic.header.type + frame->generic.header.version + + frame->generic.header.length; /* no ecc */ + /* Length does not include the header field nor the checksum */ + for (i = 1; i < length + 1; i++) + csum += frame->generic.body[i]; + frame->generic.body[0] = 0x100 - csum; +} + +static void dump_port_info(int hdmi_port_index) +{ + Register port = get_hdmi_port(hdmi_port_index); + uint32_t val = INREG(port); + Transcoder transcoder; + + printf("\nPort %s:\n", hdmi_port_names[hdmi_port_index]); + printf("- %sdetected\n", val & HDMI_PORT_DETECTED ? "" : "not "); + printf("- %s\n", val & HDMI_PORT_ENABLE ? "enabled" : "disabled"); + + if (!(val & HDMI_PORT_ENABLE)) + return; + + if (gen == 4) + transcoder = (val & HDMI_PORT_TRANSCODER_GEN4) >> 30; + else if (pch >= PCH_CPT) + transcoder = (val & HDMI_PORT_TRANSCODER_CPT) >> 29; + else + transcoder = (val & HDMI_PORT_TRANSCODER_IBX) >> 30; + printf("- transcoder: %s\n", transcoder_names[transcoder]); + + switch ((val & HDMI_PORT_ENCODING) >> 10) { + case 0: + printf("- mode: SDVO\n"); + break; + case 2: + printf("- mode: TMDS\n"); + break; + default: + printf("- mode: INVALID!\n"); + } + + printf("- mode: %s\n", val & HDMI_PORT_MODE ? "HDMI" : "DVI"); + printf("- audio: %s\n", val & HDMI_PORT_AUDIO ? "enabled" : "disabled"); +} + +static void dump_raw_infoframe(DipInfoFrame *frame) +{ + unsigned int i; + printf("- raw:"); + for (i = 0; i < 16; i++) { + if (i % 4 == 0) + printf("\n "); + printf(" %08x", frame->data32[i]); + } + printf("\n"); +} + +static void dump_avi_info(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipFrequency freq; + DipInfoFrame frame; + + load_infoframe(transcoder, &frame, DIP_AVI); + val = INREG(reg); + + printf("AVI InfoFrame:\n"); + + if (gen == 4) { + printf("- %sbeing transmitted\n", + val & DIP_CTL_BUFFER_TRANS_ACTIVE_GEN4 ? "" : "not "); + } + + freq = (val & DIP_CTL_FREQUENCY) >> 16; + printf("- frequency: %s\n", dip_frequency_names[freq]); + + dump_raw_infoframe(&frame); + + printf("- type: %x, version: %x, length: %x, ecc: %x, checksum: %x\n", + frame.avi.header.type, frame.avi.header.version, + frame.avi.header.length, frame.avi.header.ecc, + frame.avi.checksum); + printf("- S: %x, B: %x, A: %x, Y: %x, Rsvd0: %x\n", + frame.avi.S, frame.avi.B, frame.avi.A, frame.avi.Y, + frame.avi.Rsvd0); + printf("- R: %x, M: %x, C: %x\n", + frame.avi.R, frame.avi.M, frame.avi.C); + printf("- SC: %x, Q: %x, EC: %x, ITC: %x\n", + frame.avi.SC, frame.avi.Q, frame.avi.EC, frame.avi.ITC); + printf("- VIC: %x, Rsvd1: %x\n", frame.avi.VIC, frame.avi.Rsvd1); + printf("- PR: %x, Rsvd2: %x\n", frame.avi.PR, frame.avi.Rsvd2); + printf("- top: %x, bottom: %x, left: %x, right: %x\n", + frame.avi.top, frame.avi.bottom, frame.avi.left, + frame.avi.right); + printf("- Rsvd3: %x, Rsvd4[0]: %x, Rsvd4[1]: %x, Rsvd4[2]: %x\n", + frame.avi.Rsvd3, frame.avi.Rsvd4[0], frame.avi.Rsvd4[1], + frame.avi.Rsvd4[2]); + + if (!infoframe_valid_checksum(&frame)) + printf("Invalid InfoFrame checksum!\n"); +} + +static void dump_vendor_info(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipFrequency freq; + DipInfoFrame frame; + + load_infoframe(transcoder, &frame, DIP_VENDOR); + val = INREG(reg); + + printf("Vendor InfoFrame:\n"); + + if (gen == 4) { + printf("- %sbeing transmitted\n", + val & DIP_CTL_BUFFER_TRANS_ACTIVE_GEN4 ? "" : "not "); + } + + freq = (val & DIP_CTL_FREQUENCY) >> 16; + printf("- frequency: %s\n", dip_frequency_names[freq]); + + dump_raw_infoframe(&frame); + + if (!infoframe_valid_checksum(&frame)) + printf("Invalid InfoFrame checksum!\n"); +} + +static void dump_gamut_info(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipFrequency freq; + DipInfoFrame frame; + + load_infoframe(transcoder, &frame, DIP_GAMUT); + val = INREG(reg); + + printf("Gamut InfoFrame:\n"); + + if (gen == 4) { + printf("- %sbeing transmitted\n", + val & DIP_CTL_BUFFER_TRANS_ACTIVE_GEN4 ? "" : "not "); + } + + freq = (val & DIP_CTL_FREQUENCY) >> 16; + printf("- frequency: %s\n", dip_frequency_names[freq]); + + dump_raw_infoframe(&frame); + + if (!infoframe_valid_checksum(&frame)) + printf("Invalid InfoFrame checksum!\n"); +} + +static void dump_spd_info(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipFrequency freq; + DipInfoFrame frame; + char vendor[9]; + char description[17]; + + load_infoframe(transcoder, &frame, DIP_SPD); + val = INREG(reg); + + printf("SPD InfoFrame:\n"); + + if (gen == 4) { + printf("- %sbeing transmitted\n", + val & DIP_CTL_BUFFER_TRANS_ACTIVE_GEN4 ? "" : "not "); + } + + freq = (val & DIP_CTL_FREQUENCY) >> 16; + printf("- frequency: %s\n", dip_frequency_names[freq]); + + dump_raw_infoframe(&frame); + + printf("- type: %x, version: %x, length: %x, ecc: %x, checksum: %x\n", + frame.spd.header.type, frame.spd.header.version, + frame.spd.header.length, frame.spd.header.ecc, + frame.spd.checksum); + + memcpy(vendor, frame.spd.vendor, 8); + vendor[8] = '\0'; + memcpy(description, frame.spd.description, 16); + description[16] = '\0'; + + printf("- vendor: %s\n", vendor); + printf("- description: %s\n", description); + printf("- source: %s\n", spd_source_to_string(frame.spd.source)); + + if (!infoframe_valid_checksum(&frame)) + printf("Invalid InfoFrame checksum!\n"); +} + +static void dump_transcoder_info(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + + if (gen == 4) { + printf("\nDIP information:\n"); + switch (val & DIP_CTL_PORT_SEL_MASK_GEN4) { + case DIP_CTL_PORT_SEL_B_GEN4: + printf("- port B\n"); + break; + case DIP_CTL_PORT_SEL_C_GEN4: + printf("- port C\n"); + break; + default: + printf("- INVALID port!\n"); + } + } else { + printf("\nTranscoder %s:\n", transcoder_names[transcoder]); + } + printf("- %s\n", val & DIP_CTL_ENABLE ? "enabled" : "disabled"); + if (!(val & DIP_CTL_ENABLE)) + return; + + printf("- GCP: %s\n", val & DIP_CTL_GCP_ENABLE ? + "enabled" : "disabled"); + + if (val & DIP_CTL_AVI_ENABLE) + dump_avi_info(transcoder); + if (val & DIP_CTL_VENDOR_ENABLE) + dump_vendor_info(transcoder); + if (val & DIP_CTL_GAMUT_ENABLE) + dump_gamut_info(transcoder); + if (val & DIP_CTL_SPD_ENABLE) + dump_spd_info(transcoder); +} + +static void dump_all_info(void) +{ + unsigned int i; + + if (gen == 4) { + for (i = 0; i < ARRAY_SIZE(gen4_hdmi_ports); i++) + dump_port_info(i); + dump_transcoder_info(0); + } else { + for (i = 0; i < ARRAY_SIZE(pch_hdmi_ports); i++) + dump_port_info(i); + for (i = 0; i < ARRAY_SIZE(pch_dip_ctl_regs); i++) + dump_transcoder_info(i); + } +} + +static void write_infoframe(Transcoder transcoder, DipType type, + DipInfoFrame *frame) +{ + Register ctl_reg = get_dip_ctl_reg(transcoder); + Register data_reg = get_dip_data_reg(transcoder); + uint32_t ctl_val; + unsigned int i; + + ctl_val = INREG(ctl_reg); + ctl_val &= ~DIP_CTL_BUFFER_INDEX; + ctl_val |= (type << 19); + ctl_val &= ~DIP_CTL_ACCESS_ADDR; + OUTREG(ctl_reg, ctl_val); + + for (i = 0; i < 8; i++) { + ctl_val = INREG(ctl_reg); + assert((ctl_val & DIP_CTL_ACCESS_ADDR) == i); + OUTREG(data_reg, frame->data32[i]); + } +} + +static void disable_infoframe(Transcoder transcoder, DipType type) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + if (gen != 4 && type == DIP_AVI) + val &= ~DIP_CTL_ENABLE; + val &= ~(1 << (21 + type)); + OUTREG(reg, val); +} + +static void enable_infoframe(Transcoder transcoder, DipType type) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + if (gen != 4 && type == DIP_AVI) + val |= DIP_CTL_ENABLE; + val |= (1 << (21 + type)); + OUTREG(reg, val); +} + +static int parse_infoframe_option_u(const char *name, const char *s, + uint32_t min, uint32_t max, + uint32_t *value, char **commands) +{ + int read, rc; + if (!strcmp(name, s)) { + rc = sscanf(*commands, "%x%n", value, &read); + *commands = &(*commands)[read]; + if (rc != 1) { + printf("Invalid value.\n"); + return 0; + } + + if (*value < min || *value > max) { + printf("Value outside allowed range.\n"); + return 0; + } + return 1; + } + return 0; +} + +static int parse_infoframe_option_s(const char *name, const char *s, + int min_size, int max_size, + char *value, char **commands) +{ + int size, read, rc; + if (!strcmp(name, s)) { + rc = sscanf(*commands, "%31s%n", value, &read); + *commands = &(*commands)[read]; + if (rc != 1) { + printf("Invalid value.\n"); + return 0; + } + + size = strlen(value); + if (size < min_size || size > max_size) { + printf("String either too big or too small.\n"); + return 0; + } + return 1; + } + return 0; +} + +static void change_avi_infoframe(Transcoder transcoder, char *commands) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipInfoFrame frame; + char option[32]; + uint32_t option_val; + int rc, read; + char *current = commands; + + load_infoframe(transcoder, &frame, DIP_AVI); + val = INREG(reg); + + while (1) { + rc = sscanf(current, "%31s%n", option, &read); + current = ¤t[read]; + if (rc == EOF) { + break; + } else if (rc != 1) { + printf("Invalid option: %s\n", option); + continue; + } + + if (parse_infoframe_option_u("S", option, 0, 2, &option_val, + ¤t)) + frame.avi.S = option_val; + else if (parse_infoframe_option_u("B", option, 0, 3, + &option_val, ¤t)) + frame.avi.B = option_val; + else if (parse_infoframe_option_u("A", option, 0, 1, + &option_val, ¤t)) + frame.avi.A = option_val; + else if (parse_infoframe_option_u("Y", option, 0, 2, + &option_val, ¤t)) + frame.avi.Y = option_val; + else if (parse_infoframe_option_u("R", option, 0, 15, + &option_val, ¤t)) + frame.avi.R = option_val; + else if (parse_infoframe_option_u("M", option, 0, 2, + &option_val, ¤t)) + frame.avi.M = option_val; + else if (parse_infoframe_option_u("C", option, 0, 3, + &option_val, ¤t)) + frame.avi.C = option_val; + else if (parse_infoframe_option_u("SC", option, 0, 3, + &option_val, ¤t)) + frame.avi.SC = option_val; + else if (parse_infoframe_option_u("Q", option, 0, 2, + &option_val, ¤t)) + frame.avi.Q = option_val; + else if (parse_infoframe_option_u("EC", option, 0, 1, + &option_val,¤t)) + frame.avi.EC = option_val; + else if (parse_infoframe_option_u("ITC", option, 0, 1, + &option_val, ¤t)) + frame.avi.ITC = option_val; + else if (parse_infoframe_option_u("VIC", option, 0, 127, + &option_val, ¤t)) + frame.avi.VIC = option_val; + else if (parse_infoframe_option_u("PR", option, 0, 15, + &option_val, ¤t)) + frame.avi.PR = option_val; + else if (parse_infoframe_option_u("top", option, 0, 65535, + &option_val, ¤t)) + frame.avi.top = option_val; + else if (parse_infoframe_option_u("bottom", option, 0, 65535, + &option_val, ¤t)) + frame.avi.bottom = option_val; + else if (parse_infoframe_option_u("left", option, 0, 65535, + &option_val, ¤t)) + frame.avi.left = option_val; + else if (parse_infoframe_option_u("right", option, 0, 65535, + &option_val, ¤t)) + frame.avi.right = option_val; + else + printf("Unrecognized option: %s\n", option); + } + + val &= ~DIP_CTL_FREQUENCY; + val |= DIP_CTL_FREQ_EVERY; + OUTREG(reg, val); + + frame.avi.header.type = AVI_INFOFRAME_TYPE; + frame.avi.header.version = AVI_INFOFRAME_VERSION; + frame.avi.header.length = AVI_INFOFRAME_LENGTH; + frame.avi.Rsvd0 = 0; + frame.avi.Rsvd1 = 0; + frame.avi.Rsvd2 = 0; + frame.avi.Rsvd3 = 0; + frame.avi.Rsvd4[0] = 0; + frame.avi.Rsvd4[1] = 0; + frame.avi.Rsvd4[2] = 0; + + infoframe_fix_checksum(&frame); + + disable_infoframe(transcoder, DIP_AVI); + write_infoframe(transcoder, DIP_AVI, &frame); + enable_infoframe(transcoder, DIP_AVI); +} + +static void change_spd_infoframe(Transcoder transcoder, char *commands) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipInfoFrame frame; + char option[16]; + char option_val_s[32]; + uint32_t option_val_i; + int rc, read; + char *current = commands; + + load_infoframe(transcoder, &frame, DIP_SPD); + val = INREG(reg); + + while (1) { + rc = sscanf(current, "%31s%n", option, &read); + current = ¤t[read]; + if (rc == EOF) { + break; + } else if (rc != 1) { + printf("Invalid option: %s\n", option); + continue; + } + + memset(option_val_s, 0, 32); + + if (parse_infoframe_option_s("vendor", option, 0, 8, + option_val_s, ¤t)) + memcpy(frame.spd.vendor, option_val_s, 8); + else if (parse_infoframe_option_s("description", option, 0, 16, + option_val_s, ¤t)) + memcpy(frame.spd.description, option_val_s, 16); + else if (parse_infoframe_option_u("source", option, 0, 0x0c, + &option_val_i, ¤t)) + frame.spd.source = option_val_i; + else + printf("Unrecognized option: %s\n", option); + } + + val &= ~DIP_CTL_FREQUENCY; + val |= DIP_CTL_FREQ_EVERY_OTHER; + OUTREG(reg, val); + + frame.spd.header.type = SPD_INFOFRAME_TYPE; + frame.spd.header.version = SPD_INFOFRAME_VERSION; + frame.spd.header.length = SPD_INFOFRAME_LENGTH; + + infoframe_fix_checksum(&frame); + + disable_infoframe(transcoder, DIP_SPD); + write_infoframe(transcoder, DIP_SPD, &frame); + enable_infoframe(transcoder, DIP_SPD); +} + +static void change_infoframe_checksum(Transcoder transcoder, DipType type, + uint32_t selected_csum) +{ + DipInfoFrame frame; + + load_infoframe(transcoder, &frame, type); + frame.generic.body[0] = selected_csum; + disable_infoframe(transcoder, type); + write_infoframe(transcoder, type, &frame); + enable_infoframe(transcoder, type); +} + +static void change_infoframe_frequency(Transcoder transcoder, DipType type, + DipFrequency frequency) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + + if (type == DIP_AVI && frequency != DIP_FREQ_EVERY_VSYNC) { + printf("Error: AVI infoframe must be sent every VSync!\n"); + frequency = DIP_FREQ_EVERY_VSYNC; + } + + val &= ~DIP_CTL_FREQUENCY; + val |= (frequency << 16); + OUTREG(reg, val); +} + +static void disable_dip(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + val &= ~DIP_CTL_ENABLE; + OUTREG(reg, val); +} + +static void enable_dip(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + val |= DIP_CTL_ENABLE; + OUTREG(reg, val); +} + +static void disable_hdmi_port(Register reg) +{ + uint32_t val = INREG(reg); + val &= ~HDMI_PORT_ENABLE; + OUTREG(reg, val); +} + +static void enable_hdmi_port(Register reg) +{ + uint32_t val = INREG(reg); + val |= HDMI_PORT_ENABLE; + OUTREG(reg, val); +} + +static void print_usage(void) +{ +printf("Options:\n" +" -d, --dump\n" +" dump information about all transcoders\n" +" -c, --change-fields [fields]\n" +" change infoframe fields from selected transcoder\n" +" -k, --change-checksum [checksum]\n" +" change infoframe checksum (value in hex)\n" +" -q, --change-frequency [frequency]\n" +" change infoframe frequency (once, everyvsync or everyothervsync)\n" +" -n, --disable\n" +" disable the selected infoframe from the selected transcoder\n" +" -N, --enable\n" +" enable the selected infoframe from the selected transcoder\n" +" -x, --disable-infoframes\n" +" disable all infoframes from selected transcoder\n" +" -X, --enable-infoframes\n" +" enable sending infoframes on the selected transcoder\n" +" -p, --disable-hdmi-port [port]\n" +" disable hdmi port on the selected transcoder (B, C or D)\n" +" -P, --enable-hdmi-port [port]\n" +" enable hdmi port on the selected transcoder (B, C or D)\n" +" -t, --transcoder\n" +" select transcoder (A, B or C)\n" +" -f, --infoframe\n" +" select infoframe (AVI, Vendor, Gamut or SPD)\n" +" -h, --help\n" +" prints this message\n" +"\n" +"Examples:\n" +"\n" +" Dump information:\n" +" intel_infoframes\n" +"\n" +" Disable overscan and set ITC on transcoder B:\n" +" intel_infoframes -t B -f AVI -c 'S 2 ITC 1'\n" +"\n" +" Many actions on the same command:\n" +" - enable overscan on transcoder A\n" +" - enable overscan and change description on transcoder B\n" +" - disable all infoframes on transcoder C\n" +" - dump the resulting state:\n" +" intel_infoframes -t A -f AVI -c 'S 1' \\\n" +" -t B -f AVI -c 'S 2' \\\n" +" -f SPD -c 'description Linux' \\\n" +" -t C --disable-infoframes \\\n" +" -d\n" +"\n" +" Even more:\n" +" - print the help message\n" +" - completely disable all infoframes on all transcoders\n" +" - dump the state" +" - enable sending infoframes on transcoder B, but disable all infoframes\n" +" - enable AVI infoframes transcoder B, use underscan and declare ITC\n" +" - also enable SPD infoframes on the same transcoder, change frequency to\n" +" every vsync and change vendor, description and source\n" +" - dump the state again\n" +" intel_infoframes -h \\\n" +" -t A -x -t B -x -t C -x \\\n" +" -d \\\n" +" -t A -X -f AVI -n -f Vendor -n \\\n" +" -f Gamut -n -f SPD -n \\\n" +" -f AVI -N -c 'S 2 ITC 1'\\\n" +" -f SPD -q everyvsync \\\n" +" -c 'vendor me description mine source 0x09' \\\n" +" -d\n" +"\n" +"Infoframe fields used by the --change-fields option:\n" +" - AVI infoframe fields:\n" +" S B A Y R M C SC Q EC ITC VIC PR top bottom left right\n" +" - SPD infoframe fields:\n" +" vendor description source\n" +" - Other infoframe fields are not implemented yet.\n"); +} + +#define CHECK_TRANSCODER(transcoder) \ + if (transcoder == TRANSC_INVALID) { \ + printf("Transcoder not selected.\n"); \ + ret = 1; \ + goto out; \ + } + +#define CHECK_DIP(dip) \ + if (dip == DIP_INVALID) { \ + printf("Infoframe not selected.\n"); \ + ret = 1; \ + goto out; \ + } + +int main(int argc, char *argv[]) +{ + int opt; + int ret = 0; + struct pci_device *pci_dev; + Transcoder transcoder = TRANSC_INVALID; + DipType dip = DIP_INVALID; + Register hdmi_port; + + char short_opts[] = "dc:k:q:nNxXp:P:t:f:h"; + struct option long_opts[] = { + { "dump", no_argument, NULL, 'd' }, + { "change-fields", required_argument, NULL, 'c' }, + { "change-checksum", required_argument, NULL, 'k' }, + { "change-frequency", required_argument, NULL, 'q' }, + { "disable", no_argument, NULL, 'n' }, + { "enable", no_argument, NULL, 'N' }, + { "disable-infoframes", no_argument, NULL, 'x' }, + { "enable-infoframes", no_argument, NULL, 'X' }, + { "disable-hdmi-port", required_argument, NULL, 'p' }, + { "enable-hdmi-port", required_argument, NULL, 'P' }, + { "transcoder" , required_argument, NULL, 't' }, + { "infoframe", required_argument, NULL, 'f' }, + { "help", no_argument, NULL, 'h' }, + }; + + printf("WARNING: This is just a debugging tool! Don't expect it to work" + " perfectly: the Kernel might undo our changes.\n"); + + pci_dev = intel_get_pci_device(); + intel_register_access_init(pci_dev, 0); + intel_check_pch(); + + if (IS_GEN4(pci_dev->device_id)) + gen = 4; + else if (IS_GEN5(pci_dev->device_id)) + gen = 5; + else if (IS_GEN6(pci_dev->device_id)) + gen = 6; + else if (IS_GEN7(pci_dev->device_id)) + gen = 7; + else { + printf("This program does not support your hardware yet.\n"); + ret = 1; + goto out; + } + + while (1) { + opt = getopt_long(argc, argv, short_opts, long_opts, NULL); + if (opt == -1) + break; + + switch (opt) { + case 'd': + dump_all_info(); + break; + case 'c': + if (transcoder == TRANSC_INVALID) { + printf("Transcoder not selected.\n"); + ret = 1; + goto out; + } + switch (dip) { + case DIP_AVI: + change_avi_infoframe(transcoder, optarg); + break; + case DIP_VENDOR: + case DIP_GAMUT: + printf("Option not implemented yet.\n"); + ret = 1; + goto out; + case DIP_SPD: + change_spd_infoframe(transcoder, optarg); + break; + case DIP_INVALID: + printf("Infoframe not selected.\n"); + ret = 1; + goto out; + } + break; + case 'k': + CHECK_TRANSCODER(transcoder); + CHECK_DIP(dip); + change_infoframe_checksum(transcoder, dip, atoi(optarg)); + break; + case 'q': + CHECK_TRANSCODER(transcoder); + CHECK_DIP(dip); + if (!strcmp(optarg, "once")) + change_infoframe_frequency(transcoder, dip, + DIP_FREQ_ONCE); + else if (!strcmp(optarg, "everyvsync")) + change_infoframe_frequency(transcoder, dip, + DIP_FREQ_EVERY_VSYNC); + else if (!strcmp(optarg, "everyothervsync")) + change_infoframe_frequency(transcoder, dip, + DIP_FREQ_EVERY_OTHER_VSYNC); + else { + printf("Invalid frequency.\n"); + ret = 1; + goto out; + } + break; + case 'n': + CHECK_TRANSCODER(transcoder); + CHECK_DIP(dip); + disable_infoframe(transcoder, dip); + break; + case 'N': + CHECK_TRANSCODER(transcoder); + CHECK_DIP(dip); + enable_infoframe(transcoder, dip); + break; + case 'x': + CHECK_TRANSCODER(transcoder); + disable_dip(transcoder); + break; + case 'X': + CHECK_TRANSCODER(transcoder); + enable_dip(transcoder); + break; + case 'p': + case 'P': + if (!strcmp(optarg, "B")) + hdmi_port = get_hdmi_port(0); + else if (!strcmp(optarg, "C")) + hdmi_port = get_hdmi_port(1); + else if (!strcmp(optarg, "D")) + hdmi_port = get_hdmi_port(2); + else { + printf("Invalid HDMI port.\n"); + ret = 1; + goto out; + } + if (opt == 'p') + disable_hdmi_port(hdmi_port); + else + enable_hdmi_port(hdmi_port); + break; + case 't': + if (!strcmp(optarg, "A")) + transcoder = TRANSC_A; + else if (!strcmp(optarg, "B")) + transcoder = TRANSC_B; + else if (pch >= PCH_CPT && !strcmp(optarg, "C")) { + transcoder = TRANSC_C; + } else { + printf("Invalid transcoder.\n"); + ret = 1; + goto out; + } + break; + case 'f': + if (!strcmp(optarg, "AVI")) + dip = DIP_AVI; + else if (!strcmp(optarg, "Vendor")) + dip = DIP_VENDOR; + else if (!strcmp(optarg, "Gamut")) + dip = DIP_GAMUT; + else if (!strcmp(optarg, "SPD")) + dip = DIP_SPD; + else { + printf("Invalid infoframe.\n"); + ret = 1; + goto out; + } + break; + case 'h': + print_usage(); + break; + default: + print_usage(); + ret = 1; + goto out; + } + } + +out: + intel_register_access_fini(); + return ret; +} diff --git a/tools/intel_l3_parity.c b/tools/intel_l3_parity.c new file mode 100644 index 00000000..260c3d0c --- /dev/null +++ b/tools/intel_l3_parity.c @@ -0,0 +1,159 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Widawsky <ben@bwidawsk.net> + * + */ + +#define _GNU_SOURCE +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "intel_chipset.h" +#include "intel_gpu_tools.h" +#include "drmtest.h" + +#define NUM_BANKS 4 +#define NUM_SUBBANKS 8 +#define NUM_REGS (NUM_BANKS * NUM_SUBBANKS) + +struct __attribute__ ((__packed__)) l3_log_register { + uint32_t row0_enable : 1; + uint32_t rsvd2 : 4; + uint32_t row0 : 11; + uint32_t row1_enable : 1; + uint32_t rsvd1 : 4; + uint32_t row1 : 11; +} l3log[NUM_BANKS][NUM_SUBBANKS]; + +static void dumpit(void) +{ + int i, j; + + for (i = 0; i < NUM_BANKS; i++) { + for (j = 0; j < NUM_SUBBANKS; j++) { + struct l3_log_register *reg = &l3log[i][j]; + + if (reg->row0_enable) + printf("Row %d, Bank %d, Subbank %d is disabled\n", + reg->row0, i, j); + if (reg->row1_enable) + printf("Row %d, Bank %d, Subbank %d is disabled\n", + reg->row1, i, j); + } + } +} + +static int disable_rbs(int row, int bank, int sbank) +{ + struct l3_log_register *reg = &l3log[bank][sbank]; + + // can't map more than 2 rows + if (reg->row0_enable && reg->row1_enable) + return -1; + + // can't remap the same row twice + if ((reg->row0_enable && reg->row0 == row) || + (reg->row1_enable && reg->row1 == row)) { + return -1; + } + + if (reg->row0_enable) { + reg->row1 = row; + reg->row1_enable = 1; + } else { + reg->row0 = row; + reg->row0_enable = 1; + } + + return 0; +} + +static int do_parse(int argc, char *argv[]) +{ + int row, bank, sbank, i, ret; + + for (i = 1; i < argc; i++) { + ret = sscanf(argv[i], "%d,%d,%d", &row, &bank, &sbank); + if (ret != 3) + return i; + assert(disable_rbs(row, bank, sbank) == 0); + } + return 0; +} + +int main(int argc, char *argv[]) +{ + const int device = drm_get_card(0); + char *path; + unsigned int devid; + int drm_fd, fd, ret; + + drm_fd = drm_open_any(); + devid = intel_get_drm_devid(drm_fd); + + ret = asprintf(&path, "/sys/class/drm/card%d/l3_parity", device); + assert(ret != -1); + + fd = open(path, O_RDWR); + if (fd == -1 && IS_IVYBRIDGE(devid)) { + perror("Opening sysfs"); + exit(EXIT_FAILURE); + } else if (fd == -1) + exit(EXIT_SUCCESS); + + ret = read(fd, l3log, NUM_REGS * sizeof(uint32_t)); + if (ret == -1) { + perror("Reading sysfs"); + exit(EXIT_FAILURE); + } + + assert(lseek(fd, 0, SEEK_SET) == 0); + + if (argc == 1) { + dumpit(); + exit(EXIT_SUCCESS); + } else if (!strncmp("-c", argv[1], 2)) { + memset(l3log, 0, sizeof(l3log)); + } else { + ret = do_parse(argc, argv); + if (ret != 0) { + fprintf(stderr, "Malformed command line at %s\n", argv[ret]); + exit(EXIT_FAILURE); + } + } + + ret = write(fd, l3log, NUM_REGS * sizeof(uint32_t)); + if (ret == -1) { + perror("Writing sysfs"); + exit(EXIT_FAILURE); + } + + close(fd); + + exit(EXIT_SUCCESS); +} diff --git a/tools/intel_lid.c b/tools/intel_lid.c new file mode 100644 index 00000000..908224ee --- /dev/null +++ b/tools/intel_lid.c @@ -0,0 +1,144 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Zhenyu Wang <zhenyu.z.wang@intel.com> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <pciaccess.h> +#include <err.h> +#include <fcntl.h> +#include <unistd.h> +#include <dirent.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "intel_gpu_tools.h" +#include "intel_reg.h" +#include "intel_bios.h" + +enum lid_status { + LID_UNKNOWN = -1, + LID_OPEN, + LID_CLOSE, +}; + +#define ACPI_BUTTON "/proc/acpi/button/" +#define ACPI_LID "/proc/acpi/button/lid/" + +static int i830_lvds_acpi_lid_state(void) +{ + int fd; + DIR *button_dir; + DIR *lid_dir; + struct dirent *lid_dent; + char *state_name; + char state[64]; + enum lid_status ret = LID_UNKNOWN; + + button_dir = opendir(ACPI_BUTTON); + /* If acpi button driver is not loaded, bypass ACPI check method */ + if (button_dir == NULL) + goto out; + closedir(button_dir); + + lid_dir = opendir(ACPI_LID); + + /* no acpi lid object found */ + if (lid_dir == NULL) + goto out; + + while (1) { + lid_dent = readdir(lid_dir); + if (lid_dent == NULL) { + /* no LID object */ + closedir(lid_dir); + goto out; + } + if (strcmp(lid_dent->d_name, ".") && + strcmp(lid_dent->d_name, "..")) { + break; + } + } + state_name = malloc(strlen(ACPI_LID) + strlen(lid_dent->d_name) + 7); + memset(state_name, 0, sizeof(state_name)); + strcat(state_name, ACPI_LID); + strcat(state_name, lid_dent->d_name); + strcat(state_name, "/state"); + + closedir(lid_dir); + + if ((fd = open(state_name, O_RDONLY)) == -1) { + free(state_name); + goto out; + } + free(state_name); + if (read(fd, state, 64) == -1) { + close(fd); + goto out; + } + close(fd); + if (strstr(state, "open")) + ret = LID_OPEN; + else if (strstr(state, "closed")) + ret = LID_CLOSE; + else /* "unsupported" */ + ret = LID_UNKNOWN; + +out: + return ret; +} + +int main(int argc, char **argv) +{ + int swf14, acpi_lid; + + intel_get_mmio(intel_get_pci_device()); + + while (1) { + swf14 = INREG(SWF14); + + printf("Intel LVDS Lid status:\n"); + printf("\tSWF14(0x%x) : %s\n", swf14, + swf14 & SWF14_LID_SWITCH_EN ? "close" : "open"); + + acpi_lid = i830_lvds_acpi_lid_state(); + switch (acpi_lid) { + case LID_UNKNOWN: + printf("\tACPI Lid state : unknown\n"); + break; + case LID_OPEN: + printf("\tACPI Lid state : open\n"); + break; + case LID_CLOSE: + printf("\tACPI Lid state : close\n"); + break; + } + sleep(2); + } + return 0; +} diff --git a/tools/intel_panel_fitter.c b/tools/intel_panel_fitter.c new file mode 100644 index 00000000..f6723d17 --- /dev/null +++ b/tools/intel_panel_fitter.c @@ -0,0 +1,344 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Paulo Zanoni <paulo.r.zanoni@intel.com> + */ + +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include "intel_gpu_tools.h" + +int gen; + +uint32_t HTOTAL[] = { 0x60000, 0x61000, 0x62000 }; +uint32_t VTOTAL[] = { 0x6000C, 0x6100C, 0x6200C }; +uint32_t PIPECONF[] = { 0x70008, 0x71008, 0x72008 }; +uint32_t PIPESRC[] = { 0x6001C, 0x6101C, 0x6201C }; +uint32_t PF_CTRL1[] = { 0x68080, 0x68880, 0x69080 }; +uint32_t PF_WIN_POS[] = { 0x68070, 0x68870, 0x69070 }; +uint32_t PF_WIN_SZ[] = { 0x68074, 0x68874, 0x69074 }; + +#define PIPECONF_ENABLE (1 << 31) +#define PIPECONF_INTERLACE_MASK (7 << 21) +#define PIPECONF_PF_PD (0 << 21) +#define PIPECONF_PF_ID (1 << 21) +#define PIPECONF_IF_ID (3 << 21) + +#define HTOTAL_ACTIVE_MASK (0xFFF << 0) +#define VTOTAL_ACTIVE_MASK (0xFFF << 0) + +#define PIPESRC_HORIZ_MASK (0xFFF << 16) +#define PIPESRC_VERT_MASK (0xFFF << 0) + +/*#define PF_ENABLE (1 << 31)*/ +#define PF_PIPE_MASK (3 << 29) +#define PF_FILTER_MASK (3 << 23) +#define PF_FILTER_MED (1 << 23) +#define PF_PIPE_A (0 << 29) +#define PF_PIPE_B (1 << 29) +#define PF_PIPE_C (2 << 29) + +#define PF_WIN_SZ_X_MASK (0x1FFF << 16) +#define PF_WIN_SZ_Y_MASK (0xFFF << 0) + +struct pipe_info { + bool enabled; + bool pf_enabled; + uint32_t interlace_mode; + uint32_t tot_width; /* htotal */ + uint32_t tot_height; /* vtotal */ + uint32_t src_width; /* pipesrc.x */ + uint32_t src_height; /* pipesrc.y */ + uint32_t dst_width; /* pf_win_sz.x */ + uint32_t dst_height; /* pf_win_sz.y */ +}; + +static void read_pipe_info(int intel_pipe, struct pipe_info *info) +{ + uint32_t conf, vtotal, htotal, src, ctrl1, win_sz; + + conf = INREG(PIPECONF[intel_pipe]); + htotal = INREG(HTOTAL[intel_pipe]); + vtotal = INREG(VTOTAL[intel_pipe]); + src = INREG(PIPESRC[intel_pipe]); + ctrl1 = INREG(PF_CTRL1[intel_pipe]); + win_sz = INREG(PF_WIN_SZ[intel_pipe]); + + info->enabled = (conf & PIPECONF_ENABLE) ? true : false; + info->tot_width = (htotal & HTOTAL_ACTIVE_MASK) + 1; + info->tot_height = (vtotal & VTOTAL_ACTIVE_MASK) + 1; + info->src_width = ((src & PIPESRC_HORIZ_MASK) >> 16) + 1; + info->src_height = (src & PIPESRC_VERT_MASK) + 1; + info->interlace_mode = conf & PIPECONF_INTERLACE_MASK; + info->pf_enabled = ctrl1 & PF_ENABLE; + info->dst_width = (win_sz & PF_WIN_SZ_X_MASK) >> 16; + info->dst_height = win_sz & PF_WIN_SZ_Y_MASK; +} + +static void dump_pipe(int intel_pipe) +{ + struct pipe_info info; + + read_pipe_info(intel_pipe, &info); + + printf("\nPipe %c:\n", intel_pipe + 'A'); + + printf("- %s\n", info.enabled ? "enabled" : "disabled"); + if (!info.enabled) + return; + + switch (info.interlace_mode) { + case PIPECONF_PF_PD: + printf("- progressive\n"); + break; + case PIPECONF_PF_ID: + printf("- interlaced (progressive fetch)\n"); + break; + case PIPECONF_IF_ID: + printf("- interlaced (interlaced fetch)\n"); + break; + default: + assert(0); + } + + printf("- pf %s\n", info.pf_enabled ? "enabled" : "disabled"); + if (!info.pf_enabled) + return; + + printf("- tot %dx%d\n", info.tot_width, info.tot_height); + printf("- src %dx%d\n", info.src_width, info.src_height); + printf("- dst %dx%d\n", info.dst_width, info.dst_height); +} + +static void dump_info(void) +{ + int i; + int pipes; + + if (gen < 7) + pipes = 2; + else + pipes = 3; + + for (i = 0; i < pipes; i++) { + dump_pipe(i); + } +} + +static int change_screen_size(int intel_pipe, int x, int y) +{ + struct pipe_info info; + uint32_t dst_width, dst_height, pos_x, pos_y; + uint32_t ctrl1_val; + uint32_t win_pos_val; + uint32_t win_sz_val; + + read_pipe_info(intel_pipe, &info); + + if (x == 0) { + if (info.dst_width != 0) + dst_width = info.dst_width; + else + dst_width = info.src_width; + } else { + dst_width = x; + } + + if (y == 0) { + if (info.dst_height != 0) + dst_height = info.dst_height; + else + dst_height = info.src_height; + } else { + dst_height = y; + } + + pos_x = abs((info.tot_width - dst_width)) / 2; + pos_y = abs((info.tot_height - dst_height)) / 2; + + if (pos_x == 1) + pos_x = 0; + + if (info.src_width / (double) dst_width > 1.125) { + printf("X is too small\n"); + return 1; + } else if (info.tot_width < dst_width) { + printf("X is too big\n"); + return 1; + } else if (dst_width & 1) { + printf("X must be even\n"); + return 1; + } else if (info.src_height / (double) dst_height > 1.125) { + printf("Y is too small\n"); + return 1; + } else if (info.tot_height < dst_height) { + printf("Y is too big\n"); + return 1; + } else if (dst_height & 1) { + printf("Y must be even\n"); + return 1; + } + + printf("Changing size for pipe %c:\n" + "- width: %d -> %d\n" + "- height: %d -> %d\n" + "- pos: %dx%d\n", + intel_pipe + 'A', info.src_width, dst_width, info.src_height, + dst_height, pos_x, pos_y); + + ctrl1_val = PF_ENABLE | PF_FILTER_MED; + + /* This can break stuff if the panel fitter is already enabled for + * another pipe */ + if (gen >= 7) { + switch (intel_pipe) { + case 0: + ctrl1_val |= PF_PIPE_A; + break; + case 1: + ctrl1_val |= PF_PIPE_B; + break; + case 2: + ctrl1_val |= PF_PIPE_C; + break; + default: + assert(0); + } + } + OUTREG(PF_CTRL1[intel_pipe], ctrl1_val); + + win_pos_val = pos_x << 16; + win_pos_val |= pos_y; + OUTREG(PF_WIN_POS[intel_pipe], win_pos_val); + + win_sz_val = dst_width << 16; + win_sz_val |= dst_height; + OUTREG(PF_WIN_SZ[intel_pipe], win_sz_val); + + return 0; +} + +static int disable_panel_fitter(int intel_pipe) +{ + OUTREG(PF_CTRL1[intel_pipe], 0); + OUTREG(PF_WIN_POS[intel_pipe], 0); + OUTREG(PF_WIN_SZ[intel_pipe], 0); + return 0; +} + +static void print_usage(void) +{ + printf("Options:\n" +" -p pipe: pipe to be used (A, B or C)\n" +" -x value: final screen width size in pixels\n" +" -y value: final screen height size in pixels\n" +" -d: disable panel fitter\n" +" -l: list the current state of each pipe\n" +" -h: prints this message\n"); +} + +int main (int argc, char *argv[]) +{ + int opt; + int ret = 0; + char intel_pipe = '\0'; + int x = 0, y = 0; + bool do_disable = false, do_dump = false, do_usage = false; + struct pci_device *pci_dev; + uint32_t devid; + + printf("WARNING:\n" + "This tool is a workaround for people that don't have a Kernel " + "with overscan compensation properties: it is just a temporary " + "solution that may or may not work. Use it at your own risk.\n"); + + pci_dev = intel_get_pci_device(); + intel_register_access_init(pci_dev, 0); + devid = pci_dev->device_id; + + if (!HAS_PCH_SPLIT(devid)) { + printf("This tool was only tested on Ironlake and newer\n"); + ret = 1; + goto out; + } + if (IS_GEN5(devid)) + gen = 5; + else if (IS_GEN6(devid)) + gen = 6; + else + gen = 7; + + while ((opt = getopt(argc, argv, "p:x:y:dlh")) != -1) { + switch (opt) { + case 'p': + intel_pipe = optarg[0]; + if (intel_pipe != 'A' && intel_pipe != 'B' && + (gen <= 6 || intel_pipe != 'C')) { + printf("Invalid pipe\n"); + ret = 1; + goto out; + } + break; + case 'x': + x = atoi(optarg); + break; + case 'y': + y = atoi(optarg); + break; + case 'd': + do_disable = true; + break; + case 'l': + do_dump = true; + break; + case 'h': + do_usage = true; + break; + default: + do_usage = true; + ret = 1; + } + } + + if (do_usage) { + print_usage(); + } else if (do_dump) { + dump_info(); + } else if (intel_pipe) { + if (do_disable) + ret = disable_panel_fitter(intel_pipe - 'A'); + else + ret = change_screen_size(intel_pipe - 'A', x, y); + } else { + print_usage(); + ret = 1; + } + +out: + intel_register_access_fini(); + return ret; +} diff --git a/tools/intel_reg_checker.c b/tools/intel_reg_checker.c new file mode 100644 index 00000000..daa8d0fb --- /dev/null +++ b/tools/intel_reg_checker.c @@ -0,0 +1,399 @@ +/* Copyright © 2011 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <string.h> +#include <stdbool.h> +#include "intel_gpu_tools.h" + +static uint32_t devid; +static int gen; + +static inline uint32_t +read_reg(uint32_t reg) +{ + return *(volatile uint32_t *)((volatile char *)mmio + reg); +} + +static uint32_t +read_and_print_reg(const char *name, uint32_t reg) +{ + uint32_t val = read_reg(reg); + + printf("%s (0x%x): 0x%08x\n", name, reg, val); + + return val; +} + +static void +check_chicken_unset(const char *name, uint32_t reg) +{ + uint32_t val = read_and_print_reg(name, reg); + + + if (val != 0) { + fprintf(stderr, " WARN: chicken bits set\n"); + } else { + printf(" OK: chicken bits unset\n"); + } +} + +static void +check_bit(uint32_t val, int bit, const char *bitname, bool set) +{ + if (!!(val & (1 << bit)) != set) { + fprintf(stderr, " (bit %2d) FAIL: %s must be %s\n", + bit, bitname, set ? "set" : "unset"); + } else { + printf(" (bit %2d) OK: %s\n", bit, bitname); + } +} + +static void +check_perf_bit(uint32_t val, int bit, const char *bitname, bool set) +{ + if (!!(val & (1 << bit)) != set) { + printf(" (bit %2d) PERF: %s should be %s\n", + bit, bitname, set ? "set" : "unset"); + } else { + printf(" (bit %2d) OK: %s\n", bit, bitname); + } +} + +static void +check_mi_mode(void) +{ + /* Described in page 14-16 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + + uint32_t mi_mode = read_and_print_reg("MI_MODE", 0x209c); + + /* From page 14: + * + * Async Flip Performance mode + * Project: All + * Default Value: 0h + * Format: U1 + * [DevSNB] This bit must be set to ‘1’ + */ + if (gen == 6) + check_bit(mi_mode, 14, "Async Flip Performance mode", true); + else + check_perf_bit(mi_mode, 14, "Async Flip Performance mode", + false); + + check_perf_bit(mi_mode, 13, "Flush Performance Mode", false); + + /* Our driver relies on MI_FLUSH, unfortunately. */ + if (gen >= 6) + check_bit(mi_mode, 12, "MI_FLUSH enable", true); + + /* From page 15: + * + * "1h: LRA mode of allocation. Used for validation purposes" + */ + if (gen < 7) + check_bit(mi_mode, 7, "Vertex Shader Cache Mode", false); + + /* From page 16: + * + * "To avoid deadlock conditions in hardware this bit + * needs to be set for normal operation. + */ + check_bit(mi_mode, 6, "Vertex Shader Timer Dispatch Enable", true); +} + +static void +check_gfx_mode(void) +{ + /* Described in page 17-19 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + uint32_t gfx_mode; + + if (gen < 6) + return; + + if (gen == 6) + gfx_mode = read_and_print_reg("GFX_MODE", 0x2520); + else + gfx_mode = read_and_print_reg("GFX_MODE", 0x229c); + + /* Our driver only updates page tables at batchbuffer + * boundaries, so we don't need TLB flushes at other times. + */ + check_perf_bit(gfx_mode, 13, "Flush TLB Invalidation Mode", true); +} + +static void +check_gt_mode(void) +{ + /* Described in page 20-22 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + uint32_t gt_mode; + + if (gen < 6) + return; + + if (gen == 6) + gt_mode = read_and_print_reg("GT_MODE", 0x20d0); + else + gt_mode = read_and_print_reg("GT_MODE", 0x7008); + + if (gen == 6) + check_perf_bit(gt_mode, 8, "Full Rate Sampler Disable", false); + + /* For DevSmallGT, this bit must be set, which means disable + * hashing. + */ + if (devid == PCI_CHIP_SANDYBRIDGE_GT1 || + devid == PCI_CHIP_SANDYBRIDGE_M_GT1) + check_bit(gt_mode, 6, "WIZ Hashing disable", true); + else if (gen == 6) + check_perf_bit(gt_mode, 6, "WIZ Hashing disable", false); + + if (gen == 6) { + check_perf_bit(gt_mode, 5, "TD Four Row Dispatch Disable", + false); + check_perf_bit(gt_mode, 4, "Full Size URB Disable", false); + check_perf_bit(gt_mode, 3, "Full Size SF FIFO Disable", false); + check_perf_bit(gt_mode, 1, "VS Quad Thread Dispatch Disable", + false); + } +} + +static void +check_cache_mode_0(void) +{ + /* Described in page 23-25 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + uint32_t cache_mode_0; + + if (gen >= 7) + cache_mode_0 = read_and_print_reg("CACHE_MODE_0", 0x7000); + else + cache_mode_0 = read_and_print_reg("CACHE_MODE_0", 0x2120); + + check_perf_bit(cache_mode_0, 15, "Sampler L2 Disable", false); + check_perf_bit(cache_mode_0, 9, "Sampler L2 TLB Prefetch Enable", true); + check_perf_bit(cache_mode_0, 8, + "Depth Related Cache Pipelined Flush Disable", false); + + /* From page 24: + * + * "If this bit is set, RCCunit will have LRA as + * replacement policy. The default value i.e. ( when this + * bit is reset ) indicates that non-LRA eviction + * policy. This bit must be reset. LRA replacement policy + * is not supported." + * + * And the same for STC Eviction Policy. + */ + check_bit(cache_mode_0, 5, "STC LRA Eviction Policy", false); + if (gen >= 6) + check_bit(cache_mode_0, 4, "RCC LRA Eviction Policy", false); + + check_perf_bit(cache_mode_0, 3, "Hierarchical Z Disable", false); + + if (gen == 6) { + check_perf_bit(cache_mode_0, 2, + "Hierarchical Z RAW Stall Optimization " + "Disable", false); + } + + /* From page 25: + * + * "This bit must be 0. Operational Flushes [DevSNB] are + * not supported in [DevSNB]. SW must flush the render + * target after front buffer rendering." + */ + check_bit(cache_mode_0, 0, "Render Cache Operational Flush", false); +} + + +static void +check_cache_mode_1(void) +{ + /* Described in page 23-25 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + uint32_t cache_mode_1; + + if (gen >= 7) + cache_mode_1 = read_and_print_reg("CACHE_MODE_1", 0x7004); + else + cache_mode_1 = read_and_print_reg("CACHE_MODE_1", 0x2124); + + if (gen >= 7) { + check_perf_bit(cache_mode_1, 13, + "STC Address Lookup Optimization Disable", + false); + } + + /* From page 24: + * + * "If this bit is set, Hizunit will have LRA as + * replacement policy. The default value i.e. (when this + * bit is reset) indicates the non-LRA eviction + * policy. For performance reasons, this bit must be + * reset." + */ + check_bit(cache_mode_1, 12, "HIZ LRA Eviction Policy", false); + + /* Page 26 describes these bits as reserved (debug only). */ + check_bit(cache_mode_1, 11, + "DAP Instruction and State Cache Invalidate", false); + check_bit(cache_mode_1, 10, + "Instruction L1 Cache and In-Flight Queue Disable", + false); + check_bit(cache_mode_1, 9, "Instruction L2 Cache Fill Buffers Disable", + false); + + + if (gen >= 7) { + check_perf_bit(cache_mode_1, 6, + "Pixel Backend sub-span collection " + "Optimization Disable", + false); + check_perf_bit(cache_mode_1, 5, "MCS Cache Disable", false); + } + check_perf_bit(cache_mode_1, 4, "Data Disable", false); + + if (gen == 6) { + /* In a later update of the documentation, it says: + * + * "[DevSNB:A0{WKA1}] [DevSNB]: This bit must be + * set for depth buffer format + * D24_UNORM_S8_UINT." + * + * XXX: Does that mean A0 only, or all DevSNB? + */ + check_perf_bit(cache_mode_1, 3, + "Depth Read Hit Write-Only Optimization " + "Disable", false); + + check_perf_bit(cache_mode_1, 2, + "Depth Cache LRA Hunt Feature Disable", + false); + } + + check_bit(cache_mode_1, 1, "Instruction and State L2 Cache Disable", + false); + check_bit(cache_mode_1, 0, "Instruction and State L1 Cache Disable", + false); +} + + +static void +check_3d_chicken4(void) +{ + /* Described in page 23-25 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + uint32_t _3d_chicken4 = read_and_print_reg("3D_CHICKEN4", 0x20d4); + + check_perf_bit(_3d_chicken4, 6, "3D Scoreboard Hashing Enable", true); + + if (_3d_chicken4 & 0x0fbf) { + fprintf(stderr, + " WARN: other non-thread deps bits set\n"); + } else { + printf(" OK: other non-thread deps bits unset\n"); + } +} + +static void +check_dpfc_control_sa(void) +{ + uint32_t dpfc_control_sa; + + if (gen != 6) + return; + + dpfc_control_sa = read_and_print_reg("DPFC_CONTROL_SA", 0x100100); + + /* This is needed for framebuffer compression for us to be + * able to access the framebuffer by the CPU through the GTT. + */ + check_bit(dpfc_control_sa, 29, "CPU Fence Enable", true); +} + +int main(int argc, char** argv) +{ + struct pci_device *dev; + + dev = intel_get_pci_device(); + devid = dev->device_id; + intel_get_mmio(dev); + + if (IS_GEN7(devid)) + gen = 7; + else if (IS_GEN6(devid)) + gen = 6; + else if (IS_GEN5(devid)) + gen = 5; + else + gen = 4; + + check_mi_mode(); + check_gfx_mode(); + check_gt_mode(); + check_cache_mode_0(); + check_cache_mode_1(); + + if (gen < 7) { + check_chicken_unset("3D_CHICKEN", 0x2084); + check_chicken_unset("3D_CHICKEN2", 0x208c); + } else { + check_chicken_unset("FF_SLICE_CHICKEN", 0x2088); + } + if (gen >= 6) + check_chicken_unset("3D_CHICKEN3", 0x2090); + if (gen == 6) + check_3d_chicken4(); + + if (gen >= 7) { + check_chicken_unset("FF_SLICE_CS_CHICKEN1", 0x20e0); + check_chicken_unset("FF_SLICE_CS_CHICKEN2", 0x20e4); + check_chicken_unset("FF_SLICE_CS_CHICKEN3", 0x20e8); + check_chicken_unset("COMMON_SLICE_CHICKEN1", 0x7010); + check_chicken_unset("COMMON_SLICE_CHICKEN2", 0x7014); + check_chicken_unset("WM_CHICKEN", 0x5580); + check_chicken_unset("HALF_SLICE_CHICKEN", 0xe100); + check_chicken_unset("HALF_SLICE_CHICKEN2", 0xe180); + check_chicken_unset("ROW_CHICKEN", 0xe4f0); + check_chicken_unset("ROW_CHICKEN2", 0xe4f4); + } + + check_chicken_unset("ECOSKPD", 0x21d0); + + check_dpfc_control_sa(); + + return 0; +} + diff --git a/tools/intel_reg_dumper.c b/tools/intel_reg_dumper.c new file mode 100644 index 00000000..b49d967b --- /dev/null +++ b/tools/intel_reg_dumper.c @@ -0,0 +1,2246 @@ +/* + * Copyright © 2006,2009 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#define _GNU_SOURCE +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <unistd.h> +#include "intel_gpu_tools.h" + +static uint32_t devid = 0; + +#define DEBUGSTRING(func) static void func(char *result, int len, int reg, uint32_t val) + +DEBUGSTRING(i830_16bit_func) +{ + snprintf(result, len, "0x%04x", (uint16_t) val); +} + +DEBUGSTRING(i830_debug_dcc) +{ + const char *addressing = NULL; + + if (!IS_MOBILE(devid)) + return; + + if (IS_965(devid)) { + if (val & (1 << 1)) + addressing = "dual channel interleaved"; + else + addressing = "single or dual channel asymmetric"; + } else { + switch (val & 3) { + case 0: + addressing = "single channel"; + break; + case 1: + addressing = "dual channel asymmetric"; + break; + case 2: + addressing = "dual channel interleaved"; + break; + case 3: + addressing = "unknown channel layout"; + break; + } + } + + snprintf(result, len, "%s, XOR randomization: %sabled, XOR bit: %d", + addressing, + (val & (1 << 10)) ? "dis" : "en", + (val & (1 << 9)) ? 17 : 11); +} + +DEBUGSTRING(i830_debug_chdecmisc) +{ + const char *enhmodesel = NULL; + + switch ((val >> 5) & 3) { + case 1: + enhmodesel = "XOR bank/rank"; + break; + case 2: + enhmodesel = "swap bank"; + break; + case 3: + enhmodesel = "XOR bank"; + break; + case 0: + enhmodesel = "none"; + break; + } + + snprintf(result, len, + "%s, ch2 enh %sabled, ch1 enh %sabled, " + "ch0 enh %sabled, " + "flex %sabled, ep %spresent", enhmodesel, + (val & (1 << 4)) ? "en" : "dis", + (val & (1 << 3)) ? "en" : "dis", + (val & (1 << 2)) ? "en" : "dis", + (val & (1 << 1)) ? "en" : "dis", + (val & (1 << 0)) ? "" : "not "); +} + +DEBUGSTRING(i830_debug_xyminus1) +{ + snprintf(result, len, "%d, %d", (val & 0xffff) + 1, + ((val & 0xffff0000) >> 16) + 1); +} + +DEBUGSTRING(i830_debug_yxminus1) +{ + snprintf(result, len, "%d, %d", ((val & 0xffff0000) >> 16) + 1, + (val & 0xffff) + 1); +} + +DEBUGSTRING(i830_debug_xy) +{ + snprintf(result, len, "%d, %d", (val & 0xffff), ((val & 0xffff0000) >> 16)); +} + +DEBUGSTRING(i830_debug_dspstride) +{ + snprintf(result, len, "%d bytes", val); +} + +DEBUGSTRING(i830_debug_dspcntr) +{ + const char *enabled = val & DISPLAY_PLANE_ENABLE ? "enabled" : "disabled"; + char plane = val & DISPPLANE_SEL_PIPE_B ? 'B' : 'A'; + if (HAS_PCH_SPLIT(devid)) + snprintf(result, len, "%s", enabled); + else + snprintf(result, len, "%s, pipe %c", enabled, plane); +} + +DEBUGSTRING(i830_debug_pipeconf) +{ + const char *enabled = val & PIPEACONF_ENABLE ? "enabled" : "disabled"; + const char *bit30, *interlace; + + if (IS_965(devid)) + bit30 = val & I965_PIPECONF_ACTIVE ? "active" : "inactive"; + else + bit30 = + val & PIPEACONF_DOUBLE_WIDE ? "double-wide" : "single-wide"; + + if (HAS_PCH_SPLIT(devid)) { + const char *bpc, *rotation; + + switch ((val >> 21) & 7) { + case 0: + interlace = "pf-pd"; + break; + case 1: + interlace = "pf-id"; + break; + case 3: + interlace = "if-id"; + break; + case 4: + interlace = "if-id-dbl"; + break; + case 5: + interlace = "pf-id-dbl"; + break; + default: + interlace = "rsvd"; + break; + } + + switch ((val >> 14) & 3) { + case 0: + rotation = "rotate 0"; + break; + case 1: + rotation = "rotate 90"; + break; + case 2: + rotation = "rotate 180"; + break; + case 3: + rotation = "rotate 270"; + break; + } + + switch (val & (7 << 5)) { + case PIPECONF_8BPP: + bpc = "8bpc"; + break; + case PIPECONF_10BPP: + bpc = "10bpc"; + break; + case PIPECONF_6BPP: + bpc = "6bpc"; + break; + case PIPECONF_12BPP: + bpc = "12bpc"; + break; + default: + bpc = "invalid bpc"; + break; + } + snprintf(result, len, "%s, %s, %s, %s, %s", enabled, bit30, + interlace, rotation, bpc); + } else if (IS_GEN4(devid)) { + switch ((val >> 21) & 7) { + case 0: + case 1: + case 2: + case 3: + interlace = "progressive"; + break; + case 4: + interlace = "interlaced embedded"; + break; + case 5: + interlace = "interlaced"; + break; + case 6: + interlace = "interlaced sdvo"; + break; + case 7: + interlace = "interlaced legacy"; + break; + } + snprintf(result, len, "%s, %s, %s", enabled, bit30, interlace); + } else + snprintf(result, len, "%s, %s", enabled, bit30); +} + +DEBUGSTRING(i830_debug_pipestat) +{ + const char *_FIFO_UNDERRUN = val & FIFO_UNDERRUN ? " FIFO_UNDERRUN" : ""; + const char *_CRC_ERROR_ENABLE = + val & CRC_ERROR_ENABLE ? " CRC_ERROR_ENABLE" : ""; + const char *_CRC_DONE_ENABLE = + val & CRC_DONE_ENABLE ? " CRC_DONE_ENABLE" : ""; + const char *_GMBUS_EVENT_ENABLE = + val & GMBUS_EVENT_ENABLE ? " GMBUS_EVENT_ENABLE" : ""; + const char *_VSYNC_INT_ENABLE = + val & VSYNC_INT_ENABLE ? " VSYNC_INT_ENABLE" : ""; + const char *_DLINE_COMPARE_ENABLE = + val & DLINE_COMPARE_ENABLE ? " DLINE_COMPARE_ENABLE" : ""; + const char *_DPST_EVENT_ENABLE = + val & DPST_EVENT_ENABLE ? " DPST_EVENT_ENABLE" : ""; + const char *_LBLC_EVENT_ENABLE = + val & LBLC_EVENT_ENABLE ? " LBLC_EVENT_ENABLE" : ""; + const char *_OFIELD_INT_ENABLE = + val & OFIELD_INT_ENABLE ? " OFIELD_INT_ENABLE" : ""; + const char *_EFIELD_INT_ENABLE = + val & EFIELD_INT_ENABLE ? " EFIELD_INT_ENABLE" : ""; + const char *_SVBLANK_INT_ENABLE = + val & SVBLANK_INT_ENABLE ? " SVBLANK_INT_ENABLE" : ""; + const char *_VBLANK_INT_ENABLE = + val & VBLANK_INT_ENABLE ? " VBLANK_INT_ENABLE" : ""; + const char *_OREG_UPDATE_ENABLE = + val & OREG_UPDATE_ENABLE ? " OREG_UPDATE_ENABLE" : ""; + const char *_CRC_ERROR_INT_STATUS = + val & CRC_ERROR_INT_STATUS ? " CRC_ERROR_INT_STATUS" : ""; + const char *_CRC_DONE_INT_STATUS = + val & CRC_DONE_INT_STATUS ? " CRC_DONE_INT_STATUS" : ""; + const char *_GMBUS_INT_STATUS = + val & GMBUS_INT_STATUS ? " GMBUS_INT_STATUS" : ""; + const char *_VSYNC_INT_STATUS = + val & VSYNC_INT_STATUS ? " VSYNC_INT_STATUS" : ""; + const char *_DLINE_COMPARE_STATUS = + val & DLINE_COMPARE_STATUS ? " DLINE_COMPARE_STATUS" : ""; + const char *_DPST_EVENT_STATUS = + val & DPST_EVENT_STATUS ? " DPST_EVENT_STATUS" : ""; + const char *_LBLC_EVENT_STATUS = + val & LBLC_EVENT_STATUS ? " LBLC_EVENT_STATUS" : ""; + const char *_OFIELD_INT_STATUS = + val & OFIELD_INT_STATUS ? " OFIELD_INT_STATUS" : ""; + const char *_EFIELD_INT_STATUS = + val & EFIELD_INT_STATUS ? " EFIELD_INT_STATUS" : ""; + const char *_SVBLANK_INT_STATUS = + val & SVBLANK_INT_STATUS ? " SVBLANK_INT_STATUS" : ""; + const char *_VBLANK_INT_STATUS = + val & VBLANK_INT_STATUS ? " VBLANK_INT_STATUS" : ""; + const char *_OREG_UPDATE_STATUS = + val & OREG_UPDATE_STATUS ? " OREG_UPDATE_STATUS" : ""; + snprintf(result, len, + "status:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + _FIFO_UNDERRUN, + _CRC_ERROR_ENABLE, + _CRC_DONE_ENABLE, + _GMBUS_EVENT_ENABLE, + _VSYNC_INT_ENABLE, + _DLINE_COMPARE_ENABLE, + _DPST_EVENT_ENABLE, + _LBLC_EVENT_ENABLE, + _OFIELD_INT_ENABLE, + _EFIELD_INT_ENABLE, + _SVBLANK_INT_ENABLE, + _VBLANK_INT_ENABLE, + _OREG_UPDATE_ENABLE, + _CRC_ERROR_INT_STATUS, + _CRC_DONE_INT_STATUS, + _GMBUS_INT_STATUS, + _VSYNC_INT_STATUS, + _DLINE_COMPARE_STATUS, + _DPST_EVENT_STATUS, + _LBLC_EVENT_STATUS, + _OFIELD_INT_STATUS, + _EFIELD_INT_STATUS, + _SVBLANK_INT_STATUS, + _VBLANK_INT_STATUS, + _OREG_UPDATE_STATUS); +} + +DEBUGSTRING(ivb_debug_port) +{ + const char *drrs = NULL; + switch (val & (2 << 30)) { + case PORT_DBG_DRRS_HW_STATE_OFF: + drrs = "off"; + break; + case PORT_DBG_DRRS_HW_STATE_LOW: + drrs = "low"; + break; + case PORT_DBG_DRRS_HW_STATE_HIGH: + drrs = "high"; + break; + } + snprintf(result, len, "HW DRRS %s", + drrs); +} + +DEBUGSTRING(i830_debug_hvtotal) +{ + snprintf(result, len, "%d active, %d total", + (val & 0xffff) + 1, + ((val & 0xffff0000) >> 16) + 1); +} + +DEBUGSTRING(i830_debug_hvsyncblank) +{ + snprintf(result, len, "%d start, %d end", + (val & 0xffff) + 1, + ((val & 0xffff0000) >> 16) + 1); +} + +DEBUGSTRING(i830_debug_vgacntrl) +{ + snprintf(result, len, "%s", + val & VGA_DISP_DISABLE ? "disabled" : "enabled"); +} + +DEBUGSTRING(i830_debug_fp) +{ + if (IS_IGD(devid)) { + snprintf(result, len, "n = %d, m1 = %d, m2 = %d", + ffs((val & FP_N_IGD_DIV_MASK) >> + FP_N_DIV_SHIFT) - 1, + ((val & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT), + ((val & FP_M2_IGD_DIV_MASK) >> + FP_M2_DIV_SHIFT)); + } + snprintf(result, len, "n = %d, m1 = %d, m2 = %d", + ((val & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT), + ((val & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT), + ((val & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT)); +} + +DEBUGSTRING(i830_debug_vga_pd) +{ + int vga0_p1, vga0_p2, vga1_p1, vga1_p2; + + /* XXX: i9xx version */ + + if (val & VGA0_PD_P1_DIV_2) + vga0_p1 = 2; + else + vga0_p1 = ((val & VGA0_PD_P1_MASK) >> VGA0_PD_P1_SHIFT) + 2; + vga0_p2 = (val & VGA0_PD_P2_DIV_4) ? 4 : 2; + + if (val & VGA1_PD_P1_DIV_2) + vga1_p1 = 2; + else + vga1_p1 = ((val & VGA1_PD_P1_MASK) >> VGA1_PD_P1_SHIFT) + 2; + vga1_p2 = (val & VGA1_PD_P2_DIV_4) ? 4 : 2; + + snprintf(result, len, "vga0 p1 = %d, p2 = %d, vga1 p1 = %d, p2 = %d", + vga0_p1, vga0_p2, vga1_p1, vga1_p2); +} + +DEBUGSTRING(i830_debug_pp_status) +{ + const char *status = val & PP_ON ? "on" : "off"; + const char *ready = val & PP_READY ? "ready" : "not ready"; + const char *seq = "unknown"; + + switch (val & PP_SEQUENCE_MASK) { + case PP_SEQUENCE_NONE: + seq = "idle"; + break; + case PP_SEQUENCE_ON: + seq = "on"; + break; + case PP_SEQUENCE_OFF: + seq = "off"; + break; + } + + snprintf(result, len, "%s, %s, sequencing %s", status, ready, seq); +} + +DEBUGSTRING(i830_debug_pp_control) +{ + snprintf(result, len, "power target: %s", + val & POWER_TARGET_ON ? "on" : "off"); +} + +DEBUGSTRING(i830_debug_dpll) +{ + const char *enabled = val & DPLL_VCO_ENABLE ? "enabled" : "disabled"; + const char *dvomode = val & DPLL_DVO_HIGH_SPEED ? "dvo" : "non-dvo"; + const char *vgamode = val & DPLL_VGA_MODE_DIS ? "" : ", VGA"; + const char *mode = "unknown"; + const char *clock = "unknown"; + const char *fpextra = val & DISPLAY_RATE_SELECT_FPA1 ? ", using FPx1!" : ""; + char sdvoextra[20]; + int p1, p2 = 0; + + if (IS_GEN2(devid)) { + char is_lvds = (INREG(LVDS) & LVDS_PORT_EN) && (reg == DPLL_B); + + if (is_lvds) { + mode = "LVDS"; + p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) + >> DPLL_FPA01_P1_POST_DIV_SHIFT); + if ((INREG(LVDS) & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) + p2 = 7; + else + p2 = 14; + + } else { + mode = "DAC/serial"; + if (val & PLL_P1_DIVIDE_BY_TWO) { + p1 = 2; + } else { + /* Map the number in the field to (3, 33) */ + p1 = ((val & DPLL_FPA01_P1_POST_DIV_MASK_I830) + >> DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; + } + if (val & PLL_P2_DIVIDE_BY_4) + p2 = 4; + else + p2 = 2; + } + } else { + if (IS_IGD(devid)) { + p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK_IGD) >> + DPLL_FPA01_P1_POST_DIV_SHIFT_IGD); + } else { + p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + } + switch (val & DPLL_MODE_MASK) { + case DPLLB_MODE_DAC_SERIAL: + mode = "DAC/serial"; + p2 = val & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? 5 : 10; + break; + case DPLLB_MODE_LVDS: + mode = "LVDS"; + p2 = val & DPLLB_LVDS_P2_CLOCK_DIV_7 ? 7 : 14; + break; + } + } + + switch (val & PLL_REF_INPUT_MASK) { + case PLL_REF_INPUT_DREFCLK: + clock = "default"; + break; + case PLL_REF_INPUT_TVCLKINA: + clock = "TV A"; + break; + case PLL_REF_INPUT_TVCLKINBC: + clock = "TV B/C"; + break; + case PLLB_REF_INPUT_SPREADSPECTRUMIN: + if (reg == DPLL_B) + clock = "spread spectrum"; + break; + } + + if (IS_945(devid)) { + sprintf(sdvoextra, ", SDVO mult %d", + (int)((val & SDVO_MULTIPLIER_MASK) >> + SDVO_MULTIPLIER_SHIFT_HIRES) + 1); + } else { + sdvoextra[0] = '\0'; + } + + snprintf(result, len, "%s, %s%s, %s clock, %s mode, p1 = %d, " + "p2 = %d%s%s", + enabled, dvomode, vgamode, clock, mode, p1, p2, + fpextra, sdvoextra); +} + +DEBUGSTRING(i830_debug_dpll_test) +{ + const char *dpllandiv = val & DPLLA_TEST_N_BYPASS ? ", DPLLA N bypassed" : ""; + const char *dpllamdiv = val & DPLLA_TEST_M_BYPASS ? ", DPLLA M bypassed" : ""; + const char *dpllainput = val & DPLLA_INPUT_BUFFER_ENABLE ? + "" : ", DPLLA input buffer disabled"; + const char *dpllbndiv = val & DPLLB_TEST_N_BYPASS ? ", DPLLB N bypassed" : ""; + const char *dpllbmdiv = val & DPLLB_TEST_M_BYPASS ? ", DPLLB M bypassed" : ""; + const char *dpllbinput = val & DPLLB_INPUT_BUFFER_ENABLE ? + "" : ", DPLLB input buffer disabled"; + + snprintf(result, len, "%s%s%s%s%s%s", + dpllandiv, dpllamdiv, dpllainput, + dpllbndiv, dpllbmdiv, dpllbinput); +} + +DEBUGSTRING(i830_debug_adpa) +{ + char disp_pipe = (val & ADPA_PIPE_B_SELECT) ? 'B' : 'A'; + const char *enable = (val & ADPA_DAC_ENABLE) ? "enabled" : "disabled"; + char hsync = (val & ADPA_HSYNC_ACTIVE_HIGH) ? '+' : '-'; + char vsync = (val & ADPA_VSYNC_ACTIVE_HIGH) ? '+' : '-'; + + if (HAS_CPT) + disp_pipe = val & (1<<29) ? 'B' : 'A'; + + if (HAS_PCH_SPLIT(devid)) + snprintf(result, len, "%s, transcoder %c, %chsync, %cvsync", + enable, disp_pipe, hsync, vsync); + else + snprintf(result, len, "%s, pipe %c, %chsync, %cvsync", + enable, disp_pipe, hsync, vsync); +} + +DEBUGSTRING(i830_debug_lvds) +{ + char disp_pipe = val & LVDS_PIPEB_SELECT ? 'B' : 'A'; + const char *enable = val & LVDS_PORT_EN ? "enabled" : "disabled"; + int depth; + const char *channels; + + if ((val & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) + depth = 24; + else + depth = 18; + if ((val & LVDS_B0B3_POWER_MASK) == LVDS_B0B3_POWER_UP) + channels = "2 channels"; + else + channels = "1 channel"; + + if (HAS_CPT) + disp_pipe = val & (1<<29) ? 'B' : 'A'; + + snprintf(result, len, "%s, pipe %c, %d bit, %s", + enable, disp_pipe, depth, channels); +} + +DEBUGSTRING(i830_debug_dvo) +{ + const char *enable = val & DVO_ENABLE ? "enabled" : "disabled"; + char disp_pipe = val & DVO_PIPE_B_SELECT ? 'B' : 'A'; + const char *stall; + char hsync = val & DVO_HSYNC_ACTIVE_HIGH ? '+' : '-'; + char vsync = val & DVO_VSYNC_ACTIVE_HIGH ? '+' : '-'; + + switch (val & DVO_PIPE_STALL_MASK) { + case DVO_PIPE_STALL_UNUSED: + stall = "no stall"; + break; + case DVO_PIPE_STALL: + stall = "stall"; + break; + case DVO_PIPE_STALL_TV: + stall = "TV stall"; + break; + default: + stall = "unknown stall"; + break; + } + + snprintf(result, len, "%s, pipe %c, %s, %chsync, %cvsync", + enable, disp_pipe, stall, hsync, vsync); +} + +DEBUGSTRING(i830_debug_sdvo) +{ + const char *enable = val & SDVO_ENABLE ? "enabled" : "disabled"; + char disp_pipe = val & SDVO_PIPE_B_SELECT ? 'B' : 'A'; + const char *stall = val & SDVO_STALL_SELECT ? "enabled" : "disabled"; + const char *detected = val & SDVO_DETECTED ? "" : "not "; + const char *gang = val & SDVOC_GANG_MODE ? ", gang mode" : ""; + char sdvoextra[20]; + + if (IS_915(devid)) { + sprintf(sdvoextra, ", SDVO mult %d", + (int)((val & SDVO_PORT_MULTIPLY_MASK) >> + SDVO_PORT_MULTIPLY_SHIFT) + 1); + } else { + sdvoextra[0] = '\0'; + } + + snprintf(result, len, "%s, pipe %c, stall %s, %sdetected%s%s", + enable, disp_pipe, stall, detected, sdvoextra, gang); +} + +DEBUGSTRING(i830_debug_dspclk_gate_d) +{ + const char *DPUNIT_B = val & DPUNIT_B_CLOCK_GATE_DISABLE ? " DPUNIT_B" : ""; + const char *VSUNIT = val & VSUNIT_CLOCK_GATE_DISABLE ? " VSUNIT" : ""; + const char *VRHUNIT = val & VRHUNIT_CLOCK_GATE_DISABLE ? " VRHUNIT" : ""; + const char *VRDUNIT = val & VRDUNIT_CLOCK_GATE_DISABLE ? " VRDUNIT" : ""; + const char *AUDUNIT = val & AUDUNIT_CLOCK_GATE_DISABLE ? " AUDUNIT" : ""; + const char *DPUNIT_A = val & DPUNIT_A_CLOCK_GATE_DISABLE ? " DPUNIT_A" : ""; + const char *DPCUNIT = val & DPCUNIT_CLOCK_GATE_DISABLE ? " DPCUNIT" : ""; + const char *TVRUNIT = val & TVRUNIT_CLOCK_GATE_DISABLE ? " TVRUNIT" : ""; + const char *TVCUNIT = val & TVCUNIT_CLOCK_GATE_DISABLE ? " TVCUNIT" : ""; + const char *TVFUNIT = val & TVFUNIT_CLOCK_GATE_DISABLE ? " TVFUNIT" : ""; + const char *TVEUNIT = val & TVEUNIT_CLOCK_GATE_DISABLE ? " TVEUNIT" : ""; + const char *DVSUNIT = val & DVSUNIT_CLOCK_GATE_DISABLE ? " DVSUNIT" : ""; + const char *DSSUNIT = val & DSSUNIT_CLOCK_GATE_DISABLE ? " DSSUNIT" : ""; + const char *DDBUNIT = val & DDBUNIT_CLOCK_GATE_DISABLE ? " DDBUNIT" : ""; + const char *DPRUNIT = val & DPRUNIT_CLOCK_GATE_DISABLE ? " DPRUNIT" : ""; + const char *DPFUNIT = val & DPFUNIT_CLOCK_GATE_DISABLE ? " DPFUNIT" : ""; + const char *DPBMUNIT = val & DPBMUNIT_CLOCK_GATE_DISABLE ? " DPBMUNIT" : ""; + const char *DPLSUNIT = val & DPLSUNIT_CLOCK_GATE_DISABLE ? " DPLSUNIT" : ""; + const char *DPLUNIT = val & DPLUNIT_CLOCK_GATE_DISABLE ? " DPLUNIT" : ""; + const char *DPOUNIT = val & DPOUNIT_CLOCK_GATE_DISABLE ? " DPOUNIT" : ""; + const char *DPBUNIT = val & DPBUNIT_CLOCK_GATE_DISABLE ? " DPBUNIT" : ""; + const char *DCUNIT = val & DCUNIT_CLOCK_GATE_DISABLE ? " DCUNIT" : ""; + const char *DPUNIT = val & DPUNIT_CLOCK_GATE_DISABLE ? " DPUNIT" : ""; + const char *VRUNIT = val & VRUNIT_CLOCK_GATE_DISABLE ? " VRUNIT" : ""; + const char *OVHUNIT = val & OVHUNIT_CLOCK_GATE_DISABLE ? " OVHUNIT" : ""; + const char *DPIOUNIT = val & DPIOUNIT_CLOCK_GATE_DISABLE ? " DPIOUNIT" : ""; + const char *OVFUNIT = val & OVFUNIT_CLOCK_GATE_DISABLE ? " OVFUNIT" : ""; + const char *OVBUNIT = val & OVBUNIT_CLOCK_GATE_DISABLE ? " OVBUNIT" : ""; + const char *OVRUNIT = val & OVRUNIT_CLOCK_GATE_DISABLE ? " OVRUNIT" : ""; + const char *OVCUNIT = val & OVCUNIT_CLOCK_GATE_DISABLE ? " OVCUNIT" : ""; + const char *OVUUNIT = val & OVUUNIT_CLOCK_GATE_DISABLE ? " OVUUNIT" : ""; + const char *OVLUNIT = val & OVLUNIT_CLOCK_GATE_DISABLE ? " OVLUNIT" : ""; + + snprintf(result, len, + "clock gates disabled:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + DPUNIT_B, VSUNIT, VRHUNIT, VRDUNIT, AUDUNIT, DPUNIT_A, DPCUNIT, + TVRUNIT, TVCUNIT, TVFUNIT, TVEUNIT, DVSUNIT, DSSUNIT, DDBUNIT, + DPRUNIT, DPFUNIT, DPBMUNIT, DPLSUNIT, DPLUNIT, DPOUNIT, DPBUNIT, + DCUNIT, DPUNIT, VRUNIT, OVHUNIT, DPIOUNIT, OVFUNIT, OVBUNIT, + OVRUNIT, OVCUNIT, OVUUNIT, OVLUNIT); +} + +DEBUGSTRING(i810_debug_915_fence) +{ + char format = (val & 1 << 12) ? 'Y' : 'X'; + int pitch = 128 << ((val & 0x70) >> 4); + unsigned int offset = val & 0x0ff00000; + int size = (1024 * 1024) << ((val & 0x700) >> 8); + + if (IS_965(devid) || (IS_915(devid) && reg >= FENCE_NEW)) + return; + + if (format == 'X') + pitch *= 4; + if (val & 1) { + snprintf(result, len, "enabled, %c tiled, %4d pitch, 0x%08x - 0x%08x (%dkb)", + format, pitch, offset, offset + size, + size / 1024); + } else { + snprintf(result, len, "disabled"); + } +} + +DEBUGSTRING(i810_debug_965_fence_start) +{ + const char *enable = (val & FENCE_VALID) ? " enabled" : "disabled"; + char format = (val & I965_FENCE_Y_MAJOR) ? 'Y' : 'X'; + int pitch = ((val & 0xffc) >> 2) * 128 + 128; + unsigned int offset = val & 0xfffff000; + + if (!IS_965(devid)) + return; + + snprintf(result, len, "%s, %c tile walk, %4d pitch, 0x%08x start", + enable, format, pitch, offset); +} + +DEBUGSTRING(i810_debug_965_fence_end) +{ + unsigned int end = val & 0xfffff000; + + if (!IS_965(devid)) + return; + + snprintf(result, len, " 0x%08x end", end); +} + +#define DEFINEREG(reg) \ + { reg, #reg, NULL, 0 } +#define DEFINEREG_16BIT(reg) \ + { reg, #reg, i830_16bit_func, 0 } +#define DEFINEREG2(reg, func) \ + { reg, #reg, func, 0 } + +struct reg_debug { + int reg; + const char *name; + void (*debug_output) (char *result, int len, int reg, uint32_t val); + uint32_t val; +}; + +static struct reg_debug intel_debug_regs[] = { + DEFINEREG2(DCC, i830_debug_dcc), + DEFINEREG2(CHDECMISC, i830_debug_chdecmisc), + DEFINEREG_16BIT(C0DRB0), + DEFINEREG_16BIT(C0DRB1), + DEFINEREG_16BIT(C0DRB2), + DEFINEREG_16BIT(C0DRB3), + DEFINEREG_16BIT(C1DRB0), + DEFINEREG_16BIT(C1DRB1), + DEFINEREG_16BIT(C1DRB2), + DEFINEREG_16BIT(C1DRB3), + DEFINEREG_16BIT(C0DRA01), + DEFINEREG_16BIT(C0DRA23), + DEFINEREG_16BIT(C1DRA01), + DEFINEREG_16BIT(C1DRA23), + + DEFINEREG(PGETBL_CTL), + + DEFINEREG2(VCLK_DIVISOR_VGA0, i830_debug_fp), + DEFINEREG2(VCLK_DIVISOR_VGA1, i830_debug_fp), + DEFINEREG2(VCLK_POST_DIV, i830_debug_vga_pd), + DEFINEREG2(DPLL_TEST, i830_debug_dpll_test), + DEFINEREG(CACHE_MODE_0), + DEFINEREG(D_STATE), + DEFINEREG2(DSPCLK_GATE_D, i830_debug_dspclk_gate_d), + DEFINEREG(RENCLK_GATE_D1), + DEFINEREG(RENCLK_GATE_D2), +/* DEFINEREG(RAMCLK_GATE_D), CRL only */ + DEFINEREG2(SDVOB, i830_debug_sdvo), + DEFINEREG2(SDVOC, i830_debug_sdvo), +/* DEFINEREG(UDIB_SVB_SHB_CODES), CRL only */ +/* DEFINEREG(UDIB_SHA_BLANK_CODES), CRL only */ + DEFINEREG(SDVOUDI), + DEFINEREG(DSPARB), + DEFINEREG(DSPFW1), + DEFINEREG(DSPFW2), + DEFINEREG(DSPFW3), + + DEFINEREG2(ADPA, i830_debug_adpa), + DEFINEREG2(LVDS, i830_debug_lvds), + DEFINEREG2(DVOA, i830_debug_dvo), + DEFINEREG2(DVOB, i830_debug_dvo), + DEFINEREG2(DVOC, i830_debug_dvo), + DEFINEREG(DVOA_SRCDIM), + DEFINEREG(DVOB_SRCDIM), + DEFINEREG(DVOC_SRCDIM), + + DEFINEREG(BLC_PWM_CTL), + DEFINEREG(BLC_PWM_CTL2), + + DEFINEREG2(PP_CONTROL, i830_debug_pp_control), + DEFINEREG2(PP_STATUS, i830_debug_pp_status), + DEFINEREG(PP_ON_DELAYS), + DEFINEREG(PP_OFF_DELAYS), + DEFINEREG(PP_DIVISOR), + DEFINEREG(PFIT_CONTROL), + DEFINEREG(PFIT_PGM_RATIOS), + DEFINEREG(PORT_HOTPLUG_EN), + DEFINEREG(PORT_HOTPLUG_STAT), + + DEFINEREG2(DSPACNTR, i830_debug_dspcntr), + DEFINEREG2(DSPASTRIDE, i830_debug_dspstride), + DEFINEREG2(DSPAPOS, i830_debug_xy), + DEFINEREG2(DSPASIZE, i830_debug_xyminus1), + DEFINEREG(DSPABASE), + DEFINEREG(DSPASURF), + DEFINEREG(DSPATILEOFF), + DEFINEREG2(PIPEACONF, i830_debug_pipeconf), + DEFINEREG2(PIPEASRC, i830_debug_yxminus1), + DEFINEREG2(PIPEASTAT, i830_debug_pipestat), + DEFINEREG(PIPEA_GMCH_DATA_M), + DEFINEREG(PIPEA_GMCH_DATA_N), + DEFINEREG(PIPEA_DP_LINK_M), + DEFINEREG(PIPEA_DP_LINK_N), + DEFINEREG(CURSOR_A_BASE), + DEFINEREG(CURSOR_A_CONTROL), + DEFINEREG(CURSOR_A_POSITION), + + DEFINEREG2(FPA0, i830_debug_fp), + DEFINEREG2(FPA1, i830_debug_fp), + DEFINEREG2(DPLL_A, i830_debug_dpll), + DEFINEREG(DPLL_A_MD), + DEFINEREG2(HTOTAL_A, i830_debug_hvtotal), + DEFINEREG2(HBLANK_A, i830_debug_hvsyncblank), + DEFINEREG2(HSYNC_A, i830_debug_hvsyncblank), + DEFINEREG2(VTOTAL_A, i830_debug_hvtotal), + DEFINEREG2(VBLANK_A, i830_debug_hvsyncblank), + DEFINEREG2(VSYNC_A, i830_debug_hvsyncblank), + DEFINEREG(BCLRPAT_A), + DEFINEREG(VSYNCSHIFT_A), + + DEFINEREG2(DSPBCNTR, i830_debug_dspcntr), + DEFINEREG2(DSPBSTRIDE, i830_debug_dspstride), + DEFINEREG2(DSPBPOS, i830_debug_xy), + DEFINEREG2(DSPBSIZE, i830_debug_xyminus1), + DEFINEREG(DSPBBASE), + DEFINEREG(DSPBSURF), + DEFINEREG(DSPBTILEOFF), + DEFINEREG2(PIPEBCONF, i830_debug_pipeconf), + DEFINEREG2(PIPEBSRC, i830_debug_yxminus1), + DEFINEREG2(PIPEBSTAT, i830_debug_pipestat), + DEFINEREG(PIPEB_GMCH_DATA_M), + DEFINEREG(PIPEB_GMCH_DATA_N), + DEFINEREG(PIPEB_DP_LINK_M), + DEFINEREG(PIPEB_DP_LINK_N), + DEFINEREG(CURSOR_B_BASE), + DEFINEREG(CURSOR_B_CONTROL), + DEFINEREG(CURSOR_B_POSITION), + + DEFINEREG2(FPB0, i830_debug_fp), + DEFINEREG2(FPB1, i830_debug_fp), + DEFINEREG2(DPLL_B, i830_debug_dpll), + DEFINEREG(DPLL_B_MD), + DEFINEREG2(HTOTAL_B, i830_debug_hvtotal), + DEFINEREG2(HBLANK_B, i830_debug_hvsyncblank), + DEFINEREG2(HSYNC_B, i830_debug_hvsyncblank), + DEFINEREG2(VTOTAL_B, i830_debug_hvtotal), + DEFINEREG2(VBLANK_B, i830_debug_hvsyncblank), + DEFINEREG2(VSYNC_B, i830_debug_hvsyncblank), + DEFINEREG(BCLRPAT_B), + DEFINEREG(VSYNCSHIFT_B), + + DEFINEREG(VCLK_DIVISOR_VGA0), + DEFINEREG(VCLK_DIVISOR_VGA1), + DEFINEREG(VCLK_POST_DIV), + DEFINEREG2(VGACNTRL, i830_debug_vgacntrl), + + DEFINEREG(TV_CTL), + DEFINEREG(TV_DAC), + DEFINEREG(TV_CSC_Y), + DEFINEREG(TV_CSC_Y2), + DEFINEREG(TV_CSC_U), + DEFINEREG(TV_CSC_U2), + DEFINEREG(TV_CSC_V), + DEFINEREG(TV_CSC_V2), + DEFINEREG(TV_CLR_KNOBS), + DEFINEREG(TV_CLR_LEVEL), + DEFINEREG(TV_H_CTL_1), + DEFINEREG(TV_H_CTL_2), + DEFINEREG(TV_H_CTL_3), + DEFINEREG(TV_V_CTL_1), + DEFINEREG(TV_V_CTL_2), + DEFINEREG(TV_V_CTL_3), + DEFINEREG(TV_V_CTL_4), + DEFINEREG(TV_V_CTL_5), + DEFINEREG(TV_V_CTL_6), + DEFINEREG(TV_V_CTL_7), + DEFINEREG(TV_SC_CTL_1), + DEFINEREG(TV_SC_CTL_2), + DEFINEREG(TV_SC_CTL_3), + DEFINEREG(TV_WIN_POS), + DEFINEREG(TV_WIN_SIZE), + DEFINEREG(TV_FILTER_CTL_1), + DEFINEREG(TV_FILTER_CTL_2), + DEFINEREG(TV_FILTER_CTL_3), + DEFINEREG(TV_CC_CONTROL), + DEFINEREG(TV_CC_DATA), + DEFINEREG(TV_H_LUMA_0), + DEFINEREG(TV_H_LUMA_59), + DEFINEREG(TV_H_CHROMA_0), + DEFINEREG(TV_H_CHROMA_59), + + DEFINEREG(FBC_CFB_BASE), + DEFINEREG(FBC_LL_BASE), + DEFINEREG(FBC_CONTROL), + DEFINEREG(FBC_COMMAND), + DEFINEREG(FBC_STATUS), + DEFINEREG(FBC_CONTROL2), + DEFINEREG(FBC_FENCE_OFF), + DEFINEREG(FBC_MOD_NUM), + + DEFINEREG(MI_MODE), + /* DEFINEREG(MI_DISPLAY_POWER_DOWN), CRL only */ + DEFINEREG(MI_ARB_STATE), + DEFINEREG(MI_RDRET_STATE), + DEFINEREG(ECOSKPD), + + DEFINEREG(DP_B), + DEFINEREG(DPB_AUX_CH_CTL), + DEFINEREG(DPB_AUX_CH_DATA1), + DEFINEREG(DPB_AUX_CH_DATA2), + DEFINEREG(DPB_AUX_CH_DATA3), + DEFINEREG(DPB_AUX_CH_DATA4), + DEFINEREG(DPB_AUX_CH_DATA5), + + DEFINEREG(DP_C), + DEFINEREG(DPC_AUX_CH_CTL), + DEFINEREG(DPC_AUX_CH_DATA1), + DEFINEREG(DPC_AUX_CH_DATA2), + DEFINEREG(DPC_AUX_CH_DATA3), + DEFINEREG(DPC_AUX_CH_DATA4), + DEFINEREG(DPC_AUX_CH_DATA5), + + DEFINEREG(DP_D), + DEFINEREG(DPD_AUX_CH_CTL), + DEFINEREG(DPD_AUX_CH_DATA1), + DEFINEREG(DPD_AUX_CH_DATA2), + DEFINEREG(DPD_AUX_CH_DATA3), + DEFINEREG(DPD_AUX_CH_DATA4), + DEFINEREG(DPD_AUX_CH_DATA5), + + DEFINEREG(AUD_CONFIG), + DEFINEREG(AUD_HDMIW_STATUS), + DEFINEREG(AUD_CONV_CHCNT), + DEFINEREG(VIDEO_DIP_CTL), + DEFINEREG(AUD_PINW_CNTR), + DEFINEREG(AUD_CNTL_ST), + DEFINEREG(AUD_PIN_CAP), + DEFINEREG(AUD_PINW_CAP), + DEFINEREG(AUD_PINW_UNSOLRESP), + DEFINEREG(AUD_OUT_DIG_CNVT), + DEFINEREG(AUD_OUT_CWCAP), + DEFINEREG(AUD_GRP_CAP), + +#define DEFINEFENCE_915(i) \ + { FENCE+i*4, "FENCE " #i, i810_debug_915_fence, 0 } +#define DEFINEFENCE_945(i) \ + { FENCE_NEW+(i - 8) * 4, "FENCE " #i, i810_debug_915_fence, 0 } + + DEFINEFENCE_915(0), + DEFINEFENCE_915(1), + DEFINEFENCE_915(2), + DEFINEFENCE_915(3), + DEFINEFENCE_915(4), + DEFINEFENCE_915(5), + DEFINEFENCE_915(6), + DEFINEFENCE_915(7), + DEFINEFENCE_945(8), + DEFINEFENCE_945(9), + DEFINEFENCE_945(10), + DEFINEFENCE_945(11), + DEFINEFENCE_945(12), + DEFINEFENCE_945(13), + DEFINEFENCE_945(14), + DEFINEFENCE_945(15), + +#define DEFINEFENCE_965(i) \ + { FENCE_NEW+i*8, "FENCE START " #i, i810_debug_965_fence_start, 0 }, \ + { FENCE_NEW+i*8+4, "FENCE END " #i, i810_debug_965_fence_end, 0 } + + DEFINEFENCE_965(0), + DEFINEFENCE_965(1), + DEFINEFENCE_965(2), + DEFINEFENCE_965(3), + DEFINEFENCE_965(4), + DEFINEFENCE_965(5), + DEFINEFENCE_965(6), + DEFINEFENCE_965(7), + DEFINEFENCE_965(8), + DEFINEFENCE_965(9), + DEFINEFENCE_965(10), + DEFINEFENCE_965(11), + DEFINEFENCE_965(12), + DEFINEFENCE_965(13), + DEFINEFENCE_965(14), + DEFINEFENCE_965(15), + + DEFINEREG(INST_PM), +}; + +DEBUGSTRING(ironlake_debug_rr_hw_ctl) +{ + snprintf(result, len, "low %d, high %d", val & RR_HW_LOW_POWER_FRAMES_MASK, + (val & RR_HW_HIGH_POWER_FRAMES_MASK) >> 8); +} + +DEBUGSTRING(ironlake_debug_m_tu) +{ + snprintf(result, len, "TU %d, val 0x%x %d", (val >> 25) + 1, val & 0xffffff, + val & 0xffffff); +} + +DEBUGSTRING(ironlake_debug_n) +{ + snprintf(result, len, "val 0x%x %d", val & 0xffffff, val & 0xffffff); +} + +DEBUGSTRING(ironlake_debug_fdi_tx_ctl) +{ + const char *train = NULL, *voltage = NULL, *pre_emphasis = NULL, *portw = + NULL; + + switch (val & FDI_LINK_TRAIN_NONE) { + case FDI_LINK_TRAIN_PATTERN_1: + train = "pattern_1"; + break; + case FDI_LINK_TRAIN_PATTERN_2: + train = "pattern_2"; + break; + case FDI_LINK_TRAIN_PATTERN_IDLE: + train = "pattern_idle"; + break; + case FDI_LINK_TRAIN_NONE: + train = "not train"; + break; + } + + if (HAS_CPT) { + /* SNB B0 */ + switch (val & (0x3f << 22)) { + case FDI_LINK_TRAIN_400MV_0DB_SNB_B: + voltage = "0.4V"; + pre_emphasis = "0dB"; + break; + case FDI_LINK_TRAIN_400MV_6DB_SNB_B: + voltage = "0.4V"; + pre_emphasis = "6dB"; + break; + case FDI_LINK_TRAIN_600MV_3_5DB_SNB_B: + voltage = "0.6V"; + pre_emphasis = "3.5dB"; + break; + case FDI_LINK_TRAIN_800MV_0DB_SNB_B: + voltage = "0.8V"; + pre_emphasis = "0dB"; + break; + } + + } else { + + switch (val & (7 << 25)) { + case FDI_LINK_TRAIN_VOLTAGE_0_4V: + voltage = "0.4V"; + break; + case FDI_LINK_TRAIN_VOLTAGE_0_6V: + voltage = "0.6V"; + break; + case FDI_LINK_TRAIN_VOLTAGE_0_8V: + voltage = "0.8V"; + break; + case FDI_LINK_TRAIN_VOLTAGE_1_2V: + voltage = "1.2V"; + break; + default: + voltage = "reserved"; + } + + switch (val & (7 << 22)) { + case FDI_LINK_TRAIN_PRE_EMPHASIS_NONE: + pre_emphasis = "none"; + break; + case FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X: + pre_emphasis = "1.5x"; + break; + case FDI_LINK_TRAIN_PRE_EMPHASIS_2X: + pre_emphasis = "2x"; + break; + case FDI_LINK_TRAIN_PRE_EMPHASIS_3X: + pre_emphasis = "3x"; + break; + default: + pre_emphasis = "reserved"; + } + + } + + switch (val & (7 << 19)) { + case FDI_DP_PORT_WIDTH_X1: + portw = "X1"; + break; + case FDI_DP_PORT_WIDTH_X2: + portw = "X2"; + break; + case FDI_DP_PORT_WIDTH_X3: + portw = "X3"; + break; + case FDI_DP_PORT_WIDTH_X4: + portw = "X4"; + break; + } + + snprintf(result, len, "%s, train pattern %s, voltage swing %s," + "pre-emphasis %s, port width %s, enhanced framing %s, FDI PLL %s, scrambing %s, master mode %s", + val & FDI_TX_ENABLE ? "enable" : "disable", + train, voltage, pre_emphasis, portw, + val & FDI_TX_ENHANCE_FRAME_ENABLE ? "enable" : + "disable", + val & FDI_TX_PLL_ENABLE ? "enable" : "disable", + val & (1 << 7) ? "disable" : "enable", + val & (1 << 0) ? "enable" : "disable"); +} + +DEBUGSTRING(ironlake_debug_fdi_rx_ctl) +{ + const char *train = NULL, *portw = NULL, *bpc = NULL; + + if (HAS_CPT) { + switch (val & FDI_LINK_TRAIN_PATTERN_MASK_CPT) { + case FDI_LINK_TRAIN_PATTERN_1_CPT: + train = "pattern_1"; + break; + case FDI_LINK_TRAIN_PATTERN_2_CPT: + train = "pattern_2"; + break; + case FDI_LINK_TRAIN_PATTERN_IDLE_CPT: + train = "pattern_idle"; + break; + case FDI_LINK_TRAIN_NORMAL_CPT: + train = "not train"; + break; + } + } else { + switch (val & FDI_LINK_TRAIN_NONE) { + case FDI_LINK_TRAIN_PATTERN_1: + train = "pattern_1"; + break; + case FDI_LINK_TRAIN_PATTERN_2: + train = "pattern_2"; + break; + case FDI_LINK_TRAIN_PATTERN_IDLE: + train = "pattern_idle"; + break; + case FDI_LINK_TRAIN_NONE: + train = "not train"; + break; + } + } + + switch (val & (7 << 19)) { + case FDI_DP_PORT_WIDTH_X1: + portw = "X1"; + break; + case FDI_DP_PORT_WIDTH_X2: + portw = "X2"; + break; + case FDI_DP_PORT_WIDTH_X3: + portw = "X3"; + break; + case FDI_DP_PORT_WIDTH_X4: + portw = "X4"; + break; + } + + switch (val & (7 << 16)) { + case FDI_8BPC: + bpc = "8bpc"; + break; + case FDI_10BPC: + bpc = "10bpc"; + break; + case FDI_6BPC: + bpc = "6bpc"; + break; + case FDI_12BPC: + bpc = "12bpc"; + break; + } + + snprintf(result, len, "%s, train pattern %s, port width %s, %s," + "link_reverse_strap_overwrite %s, dmi_link_reverse %s, FDI PLL %s," + "FS ecc %s, FE ecc %s, FS err report %s, FE err report %s," + "scrambing %s, enhanced framing %s, %s", + val & FDI_RX_ENABLE ? "enable" : "disable", + train, portw, bpc, + val & FDI_LINK_REVERSE_OVERWRITE ? "yes" : "no", + val & FDI_DMI_LINK_REVERSE_MASK ? "yes" : "no", + val & FDI_RX_PLL_ENABLE ? "enable" : "disable", + val & FDI_FS_ERR_CORRECT_ENABLE ? "enable" : "disable", + val & FDI_FE_ERR_CORRECT_ENABLE ? "enable" : "disable", + val & FDI_FS_ERR_REPORT_ENABLE ? "enable" : "disable", + val & FDI_FE_ERR_REPORT_ENABLE ? "enable" : "disable", + val & (1 << 7) ? "disable" : "enable", + val & FDI_RX_ENHANCE_FRAME_ENABLE ? "enable" : + "disable", val & FDI_SEL_PCDCLK ? "PCDClk" : "RawClk"); +} + +DEBUGSTRING(ironlake_debug_dspstride) +{ + snprintf(result, len, "%d", val >> 6); +} + +DEBUGSTRING(ironlake_debug_pch_dpll) +{ + const char *enable = val & DPLL_VCO_ENABLE ? "enable" : "disable"; + const char *highspeed = val & DPLL_DVO_HIGH_SPEED ? "yes" : "no"; + const char *mode = NULL; + const char *p2 = NULL; + int fpa0_p1, fpa1_p1; + const char *refclk = NULL; + int sdvo_mul; + + if ((val & DPLLB_MODE_LVDS) == DPLLB_MODE_LVDS) { + mode = "LVDS"; + if (val & DPLLB_LVDS_P2_CLOCK_DIV_7) + p2 = "Div 7"; + else + p2 = "Div 14"; + } else if ((val & DPLLB_MODE_LVDS) == DPLLB_MODE_DAC_SERIAL) { + mode = "Non-LVDS"; + if (val & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5) + p2 = "Div 5"; + else + p2 = "Div 10"; + } + fpa0_p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK) >> 16); + fpa1_p1 = ffs((val & DPLL_FPA1_P1_POST_DIV_MASK)); + + switch (val & PLL_REF_INPUT_MASK) { + case PLL_REF_INPUT_DREFCLK: + refclk = "default 120Mhz"; + break; + case PLL_REF_INPUT_SUPER_SSC: + refclk = "SuperSSC 120Mhz"; + break; + case PLL_REF_INPUT_TVCLKINBC: + refclk = "SDVO TVClkIn"; + break; + case PLLB_REF_INPUT_SPREADSPECTRUMIN: + refclk = "SSC"; + break; + case PLL_REF_INPUT_DMICLK: + refclk = "DMI RefCLK"; + break; + } + + sdvo_mul = ((val & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK) >> 9) + 1; + + snprintf(result, len, "%s, sdvo high speed %s, mode %s, p2 %s, " + "FPA0 P1 %d, FPA1 P1 %d, refclk %s, sdvo/hdmi mul %d", + enable, highspeed, mode, p2, fpa0_p1, fpa1_p1, refclk, + sdvo_mul); +} + +DEBUGSTRING(ironlake_debug_dref_ctl) +{ + const char *cpu_source; + const char *ssc_source = val & DREF_SSC_SOURCE_ENABLE ? "enable" : "disable"; + const char *nonspread_source = + val & DREF_NONSPREAD_SOURCE_ENABLE ? "enable" : "disable"; + const char *superspread_source = + val & DREF_SUPERSPREAD_SOURCE_ENABLE ? "enable" : "disable"; + const char *ssc4_mode = + val & DREF_SSC4_CENTERSPREAD ? "centerspread" : "downspread"; + const char *ssc1 = val & DREF_SSC1_ENABLE ? "enable" : "disable"; + const char *ssc4 = val & DREF_SSC4_ENABLE ? "enable" : "disable"; + + switch (val & DREF_CPU_SOURCE_OUTPUT_NONSPREAD) { + case DREF_CPU_SOURCE_OUTPUT_DISABLE: + cpu_source = "disable"; + break; + case DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD: + cpu_source = "downspread"; + break; + case DREF_CPU_SOURCE_OUTPUT_NONSPREAD: + cpu_source = "nonspread"; + break; + default: + cpu_source = "reserved"; + } + snprintf(result, len, "cpu source %s, ssc_source %s, nonspread_source %s, " + "superspread_source %s, ssc4_mode %s, ssc1 %s, ssc4 %s", + cpu_source, ssc_source, nonspread_source, + superspread_source, ssc4_mode, ssc1, ssc4); +} + +DEBUGSTRING(ironlake_debug_rawclk_freq) +{ + const char *tp1 = NULL, *tp2 = NULL; + + switch (val & FDL_TP1_TIMER_MASK) { + case 0: + tp1 = "0.5us"; + break; + case (1 << 12): + tp1 = "1.0us"; + break; + case (2 << 12): + tp1 = "2.0us"; + break; + case (3 << 12): + tp1 = "4.0us"; + break; + } + switch (val & FDL_TP2_TIMER_MASK) { + case 0: + tp2 = "1.5us"; + break; + case (1 << 10): + tp2 = "3.0us"; + break; + case (2 << 10): + tp2 = "6.0us"; + break; + case (3 << 10): + tp2 = "12.0us"; + break; + } + snprintf(result, len, "FDL_TP1 timer %s, FDL_TP2 timer %s, freq %d", + tp1, tp2, val & RAWCLK_FREQ_MASK); + +} + +DEBUGSTRING(ironlake_debug_fdi_rx_misc) +{ + snprintf(result, len, "FDI Delay %d", val & ((1 << 13) - 1)); +} + +DEBUGSTRING(ironlake_debug_transconf) +{ + const char *enable = val & TRANS_ENABLE ? "enable" : "disable"; + const char *state = val & TRANS_STATE_ENABLE ? "active" : "inactive"; + const char *interlace; + + switch ((val >> 21) & 7) { + case 0: + interlace = "progressive"; + break; + case 2: + if (IS_GEN5(devid)) + interlace = "interlaced sdvo"; + else + interlace = "rsvd"; + break; + case 3: + interlace = "interlaced"; + break; + default: + interlace = "rsvd"; + } + + snprintf(result, len, "%s, %s, %s", enable, state, interlace); +} + +DEBUGSTRING(ironlake_debug_panel_fitting) +{ + const char *vadapt = NULL, *filter_sel = NULL; + + switch (val & (3 << 25)) { + case 0: + vadapt = "least"; + break; + case (1 << 25): + vadapt = "moderate"; + break; + case (2 << 25): + vadapt = "reserved"; + break; + case (3 << 25): + vadapt = "most"; + break; + } + + switch (val & (3 << 23)) { + case 0: + filter_sel = "programmed"; + break; + case (1 << 23): + filter_sel = "hardcoded"; + break; + case (2 << 23): + filter_sel = "edge_enhance"; + break; + case (3 << 23): + filter_sel = "edge_soften"; + break; + } + + snprintf(result, len, + "%s, auto_scale %s, auto_scale_cal %s, v_filter %s, vadapt %s, mode %s, filter_sel %s," + "chroma pre-filter %s, vert3tap %s, v_inter_invert %s", + val & PF_ENABLE ? "enable" : "disable", + val & (1 << 30) ? "no" : "yes", + val & (1 << 29) ? "yes" : "no", + val & (1 << 28) ? "bypass" : "enable", + val & (1 << 27) ? "enable" : "disable", + vadapt, + filter_sel, + val & (1 << 22) ? "enable" : "disable", + val & (1 << 21) ? "force" : "auto", + val & (1 << 20) ? "field 0" : "field 1"); +} + +DEBUGSTRING(ironlake_debug_panel_fitting_2) +{ + snprintf(result, len, + "vscale %f", + val / (float) (1<<15)); +} + +DEBUGSTRING(ironlake_debug_panel_fitting_3) +{ + snprintf(result, len, + "vscale initial phase %f", + val / (float) (1<<15)); +} + +DEBUGSTRING(ironlake_debug_panel_fitting_4) +{ + snprintf(result, len, + "hscale %f", + val / (float) (1<<15)); +} + +DEBUGSTRING(ironlake_debug_pf_win) +{ + int a, b; + + a = (val >> 16) & 0x1fff; + b = val & 0xfff; + + snprintf(result, len, "%d, %d", a, b); +} + +DEBUGSTRING(ironlake_debug_hdmi) +{ + int disp_pipe; + const char *enable, *bpc = NULL, *encoding; + const char *mode, *audio, *vsync, *hsync, *detect; + + if (val & PORT_ENABLE) + enable = "enabled"; + else + enable = "disabled"; + + if (HAS_CPT) + disp_pipe = (val & (3<<29)) >> 29; + else + disp_pipe = (val & TRANSCODER_B) >> 29; + + switch (val & (7 << 26)) { + case COLOR_FORMAT_8bpc: + bpc = "8bpc"; + break; + case COLOR_FORMAT_12bpc: + bpc = "12bpc"; + break; + } + + if ((val & (3 << 10)) == TMDS_ENCODING) + encoding = "TMDS"; + else + encoding = "SDVO"; + + if (val & (1 << 9)) + mode = "HDMI"; + else + mode = "DVI"; + + if (val & AUDIO_ENABLE) + audio = "enabled"; + else + audio = "disabled"; + + if (val & VSYNC_ACTIVE_HIGH) + vsync = "+vsync"; + else + vsync = "-vsync"; + + if (val & HSYNC_ACTIVE_HIGH) + hsync = "+hsync"; + else + hsync = "-hsync"; + + if (val & PORT_DETECTED) + detect = "detected"; + else + detect = "non-detected"; + + snprintf(result, len, "%s pipe %c %s %s %s audio %s %s %s %s", + enable, disp_pipe + 'A', bpc, encoding, mode, audio, vsync, hsync, detect); +} + +DEBUGSTRING(snb_debug_dpll_sel) +{ + const char *transa, *transb; + const char *dplla = NULL, *dpllb = NULL; + + if (!HAS_CPT) + return; + + if (val & TRANSA_DPLL_ENABLE) { + transa = "enable"; + if (val & TRANSA_DPLLB_SEL) + dplla = "B"; + else + dplla = "A"; + } else + transa = "disable"; + + if (val & TRANSB_DPLL_ENABLE) { + transb = "enable"; + if (val & TRANSB_DPLLB_SEL) + dpllb = "B"; + else + dpllb = "A"; + } else + transb = "disable"; + + snprintf(result, len, "TransA DPLL %s (DPLL %s), TransB DPLL %s (DPLL %s)", + transa, dplla, transb, dpllb); +} + +DEBUGSTRING(snb_debug_trans_dp_ctl) +{ + const char *enable, *port = NULL, *bpc = NULL, *vsync, *hsync; + + if (!HAS_CPT) + return; + + if (val & TRANS_DP_OUTPUT_ENABLE) + enable = "enable"; + else + enable = "disable"; + + switch (val & TRANS_DP_PORT_SEL_MASK) { + case TRANS_DP_PORT_SEL_B: + port = "B"; + break; + case TRANS_DP_PORT_SEL_C: + port = "C"; + break; + case TRANS_DP_PORT_SEL_D: + port = "D"; + break; + default: + port = "none"; + break; + } + + switch (val & (7<<9)) { + case TRANS_DP_8BPC: + bpc = "8bpc"; + break; + case TRANS_DP_10BPC: + bpc = "10bpc"; + break; + case TRANS_DP_6BPC: + bpc = "6bpc"; + break; + case TRANS_DP_12BPC: + bpc = "12bpc"; + break; + } + + if (val & TRANS_DP_VSYNC_ACTIVE_HIGH) + vsync = "+vsync"; + else + vsync = "-vsync"; + + if (val & TRANS_DP_HSYNC_ACTIVE_HIGH) + hsync = "+hsync"; + else + hsync = "-hsync"; + + snprintf(result, len, "%s port %s %s %s %s", + enable, port, bpc, vsync, hsync); +} + +DEBUGSTRING(ilk_debug_pp_control) +{ + snprintf(result, len, "blacklight %s, %spower down on reset, panel %s", + (val & (1 << 2)) ? "enabled" : "disabled", + (val & (1 << 1)) ? "" : "do not ", + (val & (1 << 0)) ? "on" : "off"); +} + +static struct reg_debug ironlake_debug_regs[] = { + DEFINEREG(PGETBL_CTL), + DEFINEREG(GEN6_INSTDONE_1), + DEFINEREG(GEN6_INSTDONE_2), + DEFINEREG2(CPU_VGACNTRL, i830_debug_vgacntrl), + DEFINEREG(DIGITAL_PORT_HOTPLUG_CNTRL), + + DEFINEREG2(RR_HW_CTL, ironlake_debug_rr_hw_ctl), + + DEFINEREG(FDI_PLL_BIOS_0), + DEFINEREG(FDI_PLL_BIOS_1), + DEFINEREG(FDI_PLL_BIOS_2), + + DEFINEREG(DISPLAY_PORT_PLL_BIOS_0), + DEFINEREG(DISPLAY_PORT_PLL_BIOS_1), + DEFINEREG(DISPLAY_PORT_PLL_BIOS_2), + + DEFINEREG(FDI_PLL_FREQ_CTL), + + /* pipe B */ + + DEFINEREG2(PIPEACONF, i830_debug_pipeconf), + + DEFINEREG2(HTOTAL_A, i830_debug_hvtotal), + DEFINEREG2(HBLANK_A, i830_debug_hvsyncblank), + DEFINEREG2(HSYNC_A, i830_debug_hvsyncblank), + DEFINEREG2(VTOTAL_A, i830_debug_hvtotal), + DEFINEREG2(VBLANK_A, i830_debug_hvsyncblank), + DEFINEREG2(VSYNC_A, i830_debug_hvsyncblank), + DEFINEREG(VSYNCSHIFT_A), + DEFINEREG2(PIPEASRC, i830_debug_yxminus1), + + DEFINEREG2(PIPEA_DATA_M1, ironlake_debug_m_tu), + DEFINEREG2(PIPEA_DATA_N1, ironlake_debug_n), + DEFINEREG2(PIPEA_DATA_M2, ironlake_debug_m_tu), + DEFINEREG2(PIPEA_DATA_N2, ironlake_debug_n), + + DEFINEREG2(PIPEA_LINK_M1, ironlake_debug_n), + DEFINEREG2(PIPEA_LINK_N1, ironlake_debug_n), + DEFINEREG2(PIPEA_LINK_M2, ironlake_debug_n), + DEFINEREG2(PIPEA_LINK_N2, ironlake_debug_n), + + DEFINEREG2(DSPACNTR, i830_debug_dspcntr), + DEFINEREG(DSPABASE), + DEFINEREG2(DSPASTRIDE, ironlake_debug_dspstride), + DEFINEREG(DSPASURF), + DEFINEREG2(DSPATILEOFF, i830_debug_xy), + + /* pipe B */ + + DEFINEREG2(PIPEBCONF, i830_debug_pipeconf), + + DEFINEREG2(HTOTAL_B, i830_debug_hvtotal), + DEFINEREG2(HBLANK_B, i830_debug_hvsyncblank), + DEFINEREG2(HSYNC_B, i830_debug_hvsyncblank), + DEFINEREG2(VTOTAL_B, i830_debug_hvtotal), + DEFINEREG2(VBLANK_B, i830_debug_hvsyncblank), + DEFINEREG2(VSYNC_B, i830_debug_hvsyncblank), + DEFINEREG(VSYNCSHIFT_B), + DEFINEREG2(PIPEBSRC, i830_debug_yxminus1), + + DEFINEREG2(PIPEB_DATA_M1, ironlake_debug_m_tu), + DEFINEREG2(PIPEB_DATA_N1, ironlake_debug_n), + DEFINEREG2(PIPEB_DATA_M2, ironlake_debug_m_tu), + DEFINEREG2(PIPEB_DATA_N2, ironlake_debug_n), + + DEFINEREG2(PIPEB_LINK_M1, ironlake_debug_n), + DEFINEREG2(PIPEB_LINK_N1, ironlake_debug_n), + DEFINEREG2(PIPEB_LINK_M2, ironlake_debug_n), + DEFINEREG2(PIPEB_LINK_N2, ironlake_debug_n), + + DEFINEREG2(DSPBCNTR, i830_debug_dspcntr), + DEFINEREG(DSPBBASE), + DEFINEREG2(DSPBSTRIDE, ironlake_debug_dspstride), + DEFINEREG(DSPBSURF), + DEFINEREG2(DSPBTILEOFF, i830_debug_xy), + + /* pipe C */ + + DEFINEREG2(PIPECCONF, i830_debug_pipeconf), + + DEFINEREG2(HTOTAL_C, i830_debug_hvtotal), + DEFINEREG2(HBLANK_C, i830_debug_hvsyncblank), + DEFINEREG2(HSYNC_C, i830_debug_hvsyncblank), + DEFINEREG2(VTOTAL_C, i830_debug_hvtotal), + DEFINEREG2(VBLANK_C, i830_debug_hvsyncblank), + DEFINEREG2(VSYNC_C, i830_debug_hvsyncblank), + DEFINEREG(VSYNCSHIFT_C), + DEFINEREG2(PIPECSRC, i830_debug_yxminus1), + + DEFINEREG2(PIPEC_DATA_M1, ironlake_debug_m_tu), + DEFINEREG2(PIPEC_DATA_N1, ironlake_debug_n), + DEFINEREG2(PIPEC_DATA_M2, ironlake_debug_m_tu), + DEFINEREG2(PIPEC_DATA_N2, ironlake_debug_n), + + DEFINEREG2(PIPEC_LINK_M1, ironlake_debug_n), + DEFINEREG2(PIPEC_LINK_N1, ironlake_debug_n), + DEFINEREG2(PIPEC_LINK_M2, ironlake_debug_n), + DEFINEREG2(PIPEC_LINK_N2, ironlake_debug_n), + + DEFINEREG2(DSPCCNTR, i830_debug_dspcntr), + DEFINEREG(DSPCBASE), + DEFINEREG2(DSPCSTRIDE, ironlake_debug_dspstride), + DEFINEREG(DSPCSURF), + DEFINEREG2(DSPCTILEOFF, i830_debug_xy), + + /* Panel fitter */ + + DEFINEREG2(PFA_CTL_1, ironlake_debug_panel_fitting), + DEFINEREG2(PFA_CTL_2, ironlake_debug_panel_fitting_2), + DEFINEREG2(PFA_CTL_3, ironlake_debug_panel_fitting_3), + DEFINEREG2(PFA_CTL_4, ironlake_debug_panel_fitting_4), + DEFINEREG2(PFA_WIN_POS, ironlake_debug_pf_win), + DEFINEREG2(PFA_WIN_SIZE, ironlake_debug_pf_win), + DEFINEREG2(PFB_CTL_1, ironlake_debug_panel_fitting), + DEFINEREG2(PFB_CTL_2, ironlake_debug_panel_fitting_2), + DEFINEREG2(PFB_CTL_3, ironlake_debug_panel_fitting_3), + DEFINEREG2(PFB_CTL_4, ironlake_debug_panel_fitting_4), + DEFINEREG2(PFB_WIN_POS, ironlake_debug_pf_win), + DEFINEREG2(PFB_WIN_SIZE, ironlake_debug_pf_win), + DEFINEREG2(PFC_CTL_1, ironlake_debug_panel_fitting), + DEFINEREG2(PFC_CTL_2, ironlake_debug_panel_fitting_2), + DEFINEREG2(PFC_CTL_3, ironlake_debug_panel_fitting_3), + DEFINEREG2(PFC_CTL_4, ironlake_debug_panel_fitting_4), + DEFINEREG2(PFC_WIN_POS, ironlake_debug_pf_win), + DEFINEREG2(PFC_WIN_SIZE, ironlake_debug_pf_win), + + /* PCH */ + + DEFINEREG2(PCH_DREF_CONTROL, ironlake_debug_dref_ctl), + DEFINEREG2(PCH_RAWCLK_FREQ, ironlake_debug_rawclk_freq), + DEFINEREG(PCH_DPLL_TMR_CFG), + DEFINEREG(PCH_SSC4_PARMS), + DEFINEREG(PCH_SSC4_AUX_PARMS), + DEFINEREG2(PCH_DPLL_SEL, snb_debug_dpll_sel), + DEFINEREG(PCH_DPLL_ANALOG_CTL), + + DEFINEREG2(PCH_DPLL_A, ironlake_debug_pch_dpll), + DEFINEREG2(PCH_DPLL_B, ironlake_debug_pch_dpll), + DEFINEREG2(PCH_FPA0, i830_debug_fp), + DEFINEREG2(PCH_FPA1, i830_debug_fp), + DEFINEREG2(PCH_FPB0, i830_debug_fp), + DEFINEREG2(PCH_FPB1, i830_debug_fp), + + DEFINEREG2(TRANS_HTOTAL_A, i830_debug_hvtotal), + DEFINEREG2(TRANS_HBLANK_A, i830_debug_hvsyncblank), + DEFINEREG2(TRANS_HSYNC_A, i830_debug_hvsyncblank), + DEFINEREG2(TRANS_VTOTAL_A, i830_debug_hvtotal), + DEFINEREG2(TRANS_VBLANK_A, i830_debug_hvsyncblank), + DEFINEREG2(TRANS_VSYNC_A, i830_debug_hvsyncblank), + DEFINEREG(TRANS_VSYNCSHIFT_A), + + DEFINEREG2(TRANSA_DATA_M1, ironlake_debug_m_tu), + DEFINEREG2(TRANSA_DATA_N1, ironlake_debug_n), + DEFINEREG2(TRANSA_DATA_M2, ironlake_debug_m_tu), + DEFINEREG2(TRANSA_DATA_N2, ironlake_debug_n), + DEFINEREG2(TRANSA_DP_LINK_M1, ironlake_debug_n), + DEFINEREG2(TRANSA_DP_LINK_N1, ironlake_debug_n), + DEFINEREG2(TRANSA_DP_LINK_M2, ironlake_debug_n), + DEFINEREG2(TRANSA_DP_LINK_N2, ironlake_debug_n), + + DEFINEREG2(TRANS_HTOTAL_B, i830_debug_hvtotal), + DEFINEREG2(TRANS_HBLANK_B, i830_debug_hvsyncblank), + DEFINEREG2(TRANS_HSYNC_B, i830_debug_hvsyncblank), + DEFINEREG2(TRANS_VTOTAL_B, i830_debug_hvtotal), + DEFINEREG2(TRANS_VBLANK_B, i830_debug_hvsyncblank), + DEFINEREG2(TRANS_VSYNC_B, i830_debug_hvsyncblank), + DEFINEREG(TRANS_VSYNCSHIFT_B), + + DEFINEREG2(TRANSB_DATA_M1, ironlake_debug_m_tu), + DEFINEREG2(TRANSB_DATA_N1, ironlake_debug_n), + DEFINEREG2(TRANSB_DATA_M2, ironlake_debug_m_tu), + DEFINEREG2(TRANSB_DATA_N2, ironlake_debug_n), + DEFINEREG2(TRANSB_DP_LINK_M1, ironlake_debug_n), + DEFINEREG2(TRANSB_DP_LINK_N1, ironlake_debug_n), + DEFINEREG2(TRANSB_DP_LINK_M2, ironlake_debug_n), + DEFINEREG2(TRANSB_DP_LINK_N2, ironlake_debug_n), + + DEFINEREG2(TRANS_HTOTAL_C, i830_debug_hvtotal), + DEFINEREG2(TRANS_HBLANK_C, i830_debug_hvsyncblank), + DEFINEREG2(TRANS_HSYNC_C, i830_debug_hvsyncblank), + DEFINEREG2(TRANS_VTOTAL_C, i830_debug_hvtotal), + DEFINEREG2(TRANS_VBLANK_C, i830_debug_hvsyncblank), + DEFINEREG2(TRANS_VSYNC_C, i830_debug_hvsyncblank), + DEFINEREG(TRANS_VSYNCSHIFT_C), + + DEFINEREG2(TRANSC_DATA_M1, ironlake_debug_m_tu), + DEFINEREG2(TRANSC_DATA_N1, ironlake_debug_n), + DEFINEREG2(TRANSC_DATA_M2, ironlake_debug_m_tu), + DEFINEREG2(TRANSC_DATA_N2, ironlake_debug_n), + DEFINEREG2(TRANSC_DP_LINK_M1, ironlake_debug_n), + DEFINEREG2(TRANSC_DP_LINK_N1, ironlake_debug_n), + DEFINEREG2(TRANSC_DP_LINK_M2, ironlake_debug_n), + DEFINEREG2(TRANSC_DP_LINK_N2, ironlake_debug_n), + + DEFINEREG2(TRANSACONF, ironlake_debug_transconf), + DEFINEREG2(TRANSBCONF, ironlake_debug_transconf), + DEFINEREG2(TRANSCCONF, ironlake_debug_transconf), + + DEFINEREG2(FDI_TXA_CTL, ironlake_debug_fdi_tx_ctl), + DEFINEREG2(FDI_TXB_CTL, ironlake_debug_fdi_tx_ctl), + DEFINEREG2(FDI_TXC_CTL, ironlake_debug_fdi_tx_ctl), + DEFINEREG2(FDI_RXA_CTL, ironlake_debug_fdi_rx_ctl), + DEFINEREG2(FDI_RXB_CTL, ironlake_debug_fdi_rx_ctl), + DEFINEREG2(FDI_RXC_CTL, ironlake_debug_fdi_rx_ctl), + + DEFINEREG2(FDI_RXA_MISC, ironlake_debug_fdi_rx_misc), + DEFINEREG2(FDI_RXB_MISC, ironlake_debug_fdi_rx_misc), + DEFINEREG2(FDI_RXC_MISC, ironlake_debug_fdi_rx_misc), + DEFINEREG(FDI_RXA_TUSIZE1), + DEFINEREG(FDI_RXA_TUSIZE2), + DEFINEREG(FDI_RXB_TUSIZE1), + DEFINEREG(FDI_RXB_TUSIZE2), + DEFINEREG(FDI_RXC_TUSIZE1), + DEFINEREG(FDI_RXC_TUSIZE2), + + DEFINEREG(FDI_PLL_CTL_1), + DEFINEREG(FDI_PLL_CTL_2), + + DEFINEREG(FDI_RXA_IIR), + DEFINEREG(FDI_RXA_IMR), + DEFINEREG(FDI_RXB_IIR), + DEFINEREG(FDI_RXB_IMR), + + DEFINEREG2(PCH_ADPA, i830_debug_adpa), + DEFINEREG2(HDMIB, ironlake_debug_hdmi), + DEFINEREG2(HDMIC, ironlake_debug_hdmi), + DEFINEREG2(HDMID, ironlake_debug_hdmi), + DEFINEREG2(PCH_LVDS, i830_debug_lvds), + DEFINEREG(CPU_eDP_A), + DEFINEREG(PCH_DP_B), + DEFINEREG(PCH_DP_C), + DEFINEREG(PCH_DP_D), + DEFINEREG2(TRANS_DP_CTL_A, snb_debug_trans_dp_ctl), + DEFINEREG2(TRANS_DP_CTL_B, snb_debug_trans_dp_ctl), + DEFINEREG2(TRANS_DP_CTL_C, snb_debug_trans_dp_ctl), + + DEFINEREG(BLC_PWM_CPU_CTL2), + DEFINEREG(BLC_PWM_CPU_CTL), + DEFINEREG(BLC_PWM_PCH_CTL1), + DEFINEREG(BLC_PWM_PCH_CTL2), + + DEFINEREG2(PCH_PP_STATUS, i830_debug_pp_status), + DEFINEREG2(PCH_PP_CONTROL, ilk_debug_pp_control), + DEFINEREG(PCH_PP_ON_DELAYS), + DEFINEREG(PCH_PP_OFF_DELAYS), + DEFINEREG(PCH_PP_DIVISOR), + + DEFINEREG2(PORT_DBG, ivb_debug_port), + + DEFINEREG(RC6_RESIDENCY_TIME), + DEFINEREG(RC6p_RESIDENCY_TIME), + DEFINEREG(RC6pp_RESIDENCY_TIME), +}; + +static struct reg_debug haswell_debug_regs[] = { + /* Power wells */ + DEFINEREG(HSW_PWR_WELL_CTL1), + DEFINEREG(HSW_PWR_WELL_CTL2), + DEFINEREG(HSW_PWR_WELL_CTL3), + DEFINEREG(HSW_PWR_WELL_CTL4), + DEFINEREG(HSW_PWR_WELL_CTL5), + DEFINEREG(HSW_PWR_WELL_CTL6), + + /* DDI pipe function */ + DEFINEREG(PIPE_DDI_FUNC_CTL_A), + DEFINEREG(PIPE_DDI_FUNC_CTL_B), + DEFINEREG(PIPE_DDI_FUNC_CTL_C), + DEFINEREG(PIPE_DDI_FUNC_CTL_EDP), + + /* DP transport control */ + DEFINEREG(DP_TP_CTL_A), + DEFINEREG(DP_TP_CTL_B), + DEFINEREG(DP_TP_CTL_C), + DEFINEREG(DP_TP_CTL_D), + DEFINEREG(DP_TP_CTL_E), + + /* DP status */ + DEFINEREG(DP_TP_STATUS_A), + DEFINEREG(DP_TP_STATUS_B), + DEFINEREG(DP_TP_STATUS_C), + DEFINEREG(DP_TP_STATUS_D), + DEFINEREG(DP_TP_STATUS_E), + + /* DDI buffer control */ + DEFINEREG(DDI_BUF_CTL_A), + DEFINEREG(DDI_BUF_CTL_B), + DEFINEREG(DDI_BUF_CTL_C), + DEFINEREG(DDI_BUF_CTL_D), + DEFINEREG(DDI_BUF_CTL_E), + + /* Clocks */ + DEFINEREG(PIXCLK_GATE), + DEFINEREG(SPLL_CTL), + DEFINEREG(LCPLL_CTL), + DEFINEREG(WRPLL_CTL1), + DEFINEREG(WRPLL_CTL2), + + /* DDI port clock control */ + DEFINEREG(PORT_CLK_SEL_A), + DEFINEREG(PORT_CLK_SEL_B), + DEFINEREG(PORT_CLK_SEL_C), + DEFINEREG(PORT_CLK_SEL_D), + DEFINEREG(PORT_CLK_SEL_E), + + /* Pipe clock control */ + DEFINEREG(PIPE_CLK_SEL_A), + DEFINEREG(PIPE_CLK_SEL_B), + DEFINEREG(PIPE_CLK_SEL_C), + + /* Pipe line time */ + DEFINEREG(PIPE_WM_LINETIME_A), + DEFINEREG(PIPE_WM_LINETIME_B), + DEFINEREG(PIPE_WM_LINETIME_C), + + /* Fuses */ + DEFINEREG(SFUSE_STRAP), + +}; + +static struct reg_debug i945gm_mi_regs[] = { + DEFINEREG(PGETBL_CTL), + DEFINEREG(PGTBL_ER), + DEFINEREG(EXCC), + DEFINEREG(HWS_PGA), + DEFINEREG(IPEIR), + DEFINEREG(IPEHR), + DEFINEREG(INST_DONE), + DEFINEREG(NOP_ID), + DEFINEREG(HWSTAM), + DEFINEREG(SCPD0), + DEFINEREG(IER), + DEFINEREG(IIR), + DEFINEREG(IMR), + DEFINEREG(ISR), + DEFINEREG(EIR), + DEFINEREG(EMR), + DEFINEREG(ESR), + DEFINEREG(INST_PM), + DEFINEREG(ECOSKPD), +}; + +#define intel_dump_regs(regs) _intel_dump_regs(regs, ARRAY_SIZE(regs)) + +static void +_intel_dump_regs(struct reg_debug *regs, int count) +{ + char debug[1024]; + int i; + + for (i = 0; i < count; i++) { + uint32_t val = INREG(regs[i].reg); + + if (regs[i].debug_output != NULL) { + regs[i].debug_output(debug, sizeof(debug), regs[i].reg, val); + printf("%30.30s: 0x%08x (%s)\n", + regs[i].name, + (unsigned int)val, debug); + } else { + printf("%30.30s: 0x%08x\n", regs[i].name, + (unsigned int)val); + } + } +} + +DEBUGSTRING(gen6_rp_control) +{ + snprintf(result, len, "%s", + (val & (1 << 7)) ? "enabled" : "disabled"); +} + +static struct reg_debug gen6_rp_debug_regs[] = { + DEFINEREG2(GEN6_RP_CONTROL, gen6_rp_control), + DEFINEREG(GEN6_RPNSWREQ), + DEFINEREG(GEN6_RP_DOWN_TIMEOUT), + DEFINEREG(GEN6_RP_INTERRUPT_LIMITS), + DEFINEREG(GEN6_RP_UP_THRESHOLD), + DEFINEREG(GEN6_RP_UP_EI), + DEFINEREG(GEN6_RP_DOWN_EI), + DEFINEREG(GEN6_RP_IDLE_HYSTERSIS), + DEFINEREG(GEN6_RC_STATE), + DEFINEREG(GEN6_RC_CONTROL), + DEFINEREG(GEN6_RC1_WAKE_RATE_LIMIT), + DEFINEREG(GEN6_RC6_WAKE_RATE_LIMIT), + DEFINEREG(GEN6_RC_EVALUATION_INTERVAL), + DEFINEREG(GEN6_RC_IDLE_HYSTERSIS), + DEFINEREG(GEN6_RC_SLEEP), + DEFINEREG(GEN6_RC1e_THRESHOLD), + DEFINEREG(GEN6_RC6_THRESHOLD), + DEFINEREG(GEN6_RC_VIDEO_FREQ), + DEFINEREG(GEN6_PMIER), + DEFINEREG(GEN6_PMIMR), + DEFINEREG(GEN6_PMINTRMSK), +}; + +static void +intel_dump_other_regs(void) +{ + int i; + int fp, dpll; + int disp_pipe; + int n, m1, m2, m, p1, p2; + int ref; + int dot; + int phase; +#if 0 + int msr; + int crt; +#endif + +#if 0 + i830DumpIndexed(pScrn, "SR", 0x3c4, 0x3c5, 0, 7); + msr = INREG8(0x3cc); + printf("%20.20s: 0x%02x\n", + "MSR", (unsigned int)msr); + + i830DumpAR(pScrn); + if (msr & 1) + crt = 0x3d0; + else + crt = 0x3b0; + i830DumpIndexed(pScrn, "CR", crt + 4, crt + 5, 0, 0x24); +#endif + for (disp_pipe = 0; disp_pipe <= 1; disp_pipe++) { + fp = INREG(disp_pipe == 0 ? FPA0 : FPB0); + dpll = INREG(disp_pipe == 0 ? DPLL_A : DPLL_B); + if (IS_GEN2(devid)) { + uint32_t lvds = INREG(LVDS); + if (devid == PCI_CHIP_I855_GM && + (lvds & LVDS_PORT_EN) && + (lvds & LVDS_PIPEB_SELECT) == (disp_pipe << 30)) { + if ((lvds & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) + p2 = 7; + else + p2 = 14; + switch ((dpll >> 16) & 0x3f) { + case 0x01: + p1 = 1; + break; + case 0x02: + p1 = 2; + break; + case 0x04: + p1 = 3; + break; + case 0x08: + p1 = 4; + break; + case 0x10: + p1 = 5; + break; + case 0x20: + p1 = 6; + break; + default: + p1 = 1; + printf("LVDS P1 0x%x invalid encoding\n", + (dpll >> 16) & 0x3f); + break; + } + } else { + if (dpll & (1 << 23)) + p2 = 4; + else + p2 = 2; + if (dpll & PLL_P1_DIVIDE_BY_TWO) + p1 = 2; + else + p1 = ((dpll >> 16) & 0x3f) + 2; + } + + switch ((dpll >> 13) & 0x3) { + case 0: + ref = 48000; + break; + case 3: + ref = 66000; + break; + default: + ref = 0; + printf("ref out of range\n"); + break; + } + } else { + uint32_t lvds = INREG(LVDS); + if ((lvds & LVDS_PORT_EN) && + (lvds & LVDS_PIPEB_SELECT) == (disp_pipe << 30)) { + if ((lvds & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) + p2 = 7; + else + p2 = 14; + } else { + switch ((dpll >> 24) & 0x3) { + case 0: + p2 = 10; + break; + case 1: + p2 = 5; + break; + default: + p2 = 1; + printf("p2 out of range\n"); + break; + } + } + if (IS_IGD(devid)) + i = (dpll >> DPLL_FPA01_P1_POST_DIV_SHIFT_IGD) & + 0x1ff; + else + i = (dpll >> DPLL_FPA01_P1_POST_DIV_SHIFT) & + 0xff; + switch (i) { + case 1: + p1 = 1; + break; + case 2: + p1 = 2; + break; + case 4: + p1 = 3; + break; + case 8: + p1 = 4; + break; + case 16: + p1 = 5; + break; + case 32: + p1 = 6; + break; + case 64: + p1 = 7; + break; + case 128: + p1 = 8; + break; + case 256: + if (IS_IGD(devid)) { + p1 = 9; + break; + } /* fallback */ + default: + p1 = 1; + printf("p1 out of range\n"); + break; + } + + switch ((dpll >> 13) & 0x3) { + case 0: + ref = 96000; + break; + case 3: + ref = 100000; + break; + default: + ref = 0; + printf("ref out of range\n"); + break; + } + } + if (IS_965(devid)) { + phase = (dpll >> 9) & 0xf; + switch (phase) { + case 6: + break; + default: + printf("SDVO phase shift %d out of range -- probobly not " + "an issue.\n", phase); + break; + } + } + switch ((dpll >> 8) & 1) { + case 0: + break; + default: + printf("fp select out of range\n"); + break; + } + m1 = ((fp >> 8) & 0x3f); + if (IS_IGD(devid)) { + n = ffs((fp & FP_N_IGD_DIV_MASK) >> FP_N_DIV_SHIFT) - 1; + m2 = (fp & FP_M2_IGD_DIV_MASK) >> FP_M2_DIV_SHIFT; + m = m2 + 2; + dot = (ref * m) / n / (p1 * p2); + } else { + n = ((fp >> 16) & 0x3f); + m2 = ((fp >> 0) & 0x3f); + m = 5 * (m1 + 2) + (m2 + 2); + dot = + (ref * (5 * (m1 + 2) + (m2 + 2)) / (n + 2)) / (p1 * + p2); + } + + printf("pipe %s dot %d n %d m1 %d m2 %d p1 %d p2 %d\n", + disp_pipe == 0 ? "A" : "B", dot, n, m1, m2, p1, p2); + } +} + +static void print_usage(void) +{ + printf("Usage: intel_reg_dumper [options] [file]\n" + "Options:\n" + " -d id when a dump file is used, use 'id' as device id (in " + "hex)\n" + " -h prints this help\n"); +} + +int main(int argc, char** argv) +{ + struct pci_device *pci_dev; + int opt; + char *file = NULL; + + while ((opt = getopt(argc, argv, "d:h")) != -1) { + switch (opt) { + case 'd': + devid = strtol(optarg, NULL, 16); + break; + case 'h': + print_usage(); + return 0; + default: + print_usage(); + return 1; + } + } + if (optind < argc) + file = argv[optind]; + + if (file) { + intel_map_file(file); + if (devid) { + if (IS_GEN5(devid)) + pch = PCH_IBX; + else + pch = PCH_CPT; + } else { + printf("Dumping from file without -d argument. " + "Assuming Ironlake machine.\n"); + devid = 0x0042; + pch = PCH_IBX; + } + } else { + pci_dev = intel_get_pci_device(); + devid = pci_dev->device_id; + + intel_register_access_init(pci_dev, 1); + + if (HAS_PCH_SPLIT(devid)) + intel_check_pch(); + } + + if (HAS_PCH_SPLIT(devid)) { + intel_dump_regs(ironlake_debug_regs); + } else if (IS_945GM(devid)) { + intel_dump_regs(i945gm_mi_regs); + intel_dump_regs(intel_debug_regs); + intel_dump_other_regs(); + } else { + intel_dump_regs(intel_debug_regs); + intel_dump_other_regs(); + } + + if (IS_GEN6(devid) || IS_GEN7(devid)) + intel_dump_regs(gen6_rp_debug_regs); + + if (IS_HASWELL(devid)) + intel_dump_regs(haswell_debug_regs); + + + intel_register_access_fini(); + return 0; +} diff --git a/tools/intel_reg_read.c b/tools/intel_reg_read.c new file mode 100644 index 00000000..ae631be0 --- /dev/null +++ b/tools/intel_reg_read.c @@ -0,0 +1,142 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Zhenyu Wang <zhenyuw@linux.intel.com> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <string.h> +#include "intel_gpu_tools.h" + +static void bit_decode(uint32_t reg) +{ + int i; + + for (i=31; i >= 0; i--) + printf(" %2d", i); + printf("\n"); + + for (i=31; i >= 0; i--) + printf(" %2d", (reg & (1 << i)) && 1); + printf("\n"); +} + +static void dump_range(uint32_t start, uint32_t end) +{ + int i; + + for (i = start; i < end; i += 4) + printf("0x%X : 0x%X\n", i, + *(volatile uint32_t *)((volatile char*)mmio + i)); +} + +static void usage(char *cmdname) +{ + printf("Usage: %s [-f|-d] [addr1] [addr2] .. [addrN]\n", cmdname); + printf("\t -f : read back full range of registers.\n"); + printf("\t WARNING! This option may result in a machine hang!\n"); + printf("\t -d : decode register bits.\n"); + printf("\t -c : number of dwords to dump (can't be used with -f/-d).\n"); + printf("\t addr : in 0xXXXX format\n"); +} + +int main(int argc, char** argv) +{ + int ret = 0; + uint32_t reg; + int i, ch; + char *cmdname = strdup(argv[0]); + int full_dump = 0; + int decode_bits = 0; + int dwords = 1; + + while ((ch = getopt(argc, argv, "dfhc:")) != -1) { + switch(ch) { + case 'd': + decode_bits = 1; + break; + case 'f': + full_dump = 1; + break; + case 'h': + usage(cmdname); + ret = 1; + goto out; + case 'c': + dwords = strtol(optarg, NULL, 0); + break; + } + } + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(cmdname); + ret = 1; + goto out; + } + + if ((dwords > 1) && (argc != 1 || full_dump || decode_bits)) { + usage(cmdname); + ret = 1; + goto out; + } + + intel_register_access_init(intel_get_pci_device(), 0); + + if (full_dump) { + dump_range(0x00000, 0x00fff); /* VGA registers */ + dump_range(0x02000, 0x02fff); /* instruction, memory, interrupt control registers */ + dump_range(0x03000, 0x031ff); /* FENCE and PPGTT control registers */ + dump_range(0x03200, 0x03fff); /* frame buffer compression registers */ + dump_range(0x05000, 0x05fff); /* I/O control registers */ + dump_range(0x06000, 0x06fff); /* clock control registers */ + dump_range(0x07000, 0x07fff); /* 3D internal debug registers */ + dump_range(0x07400, 0x088ff); /* GPE debug registers */ + dump_range(0x0a000, 0x0afff); /* display palette registers */ + dump_range(0x10000, 0x13fff); /* MMIO MCHBAR */ + dump_range(0x30000, 0x3ffff); /* overlay registers */ + dump_range(0x60000, 0x6ffff); /* display engine pipeline registers */ + dump_range(0x70000, 0x72fff); /* display and cursor registers */ + dump_range(0x73000, 0x73fff); /* performance counters */ + } else { + for (i=0; i < argc; i++) { + sscanf(argv[i], "0x%x", ®); + dump_range(reg, reg + (dwords * 4)); + + if (decode_bits) + bit_decode(*(volatile uint32_t *)((volatile char*)mmio + reg)); + } + } + + intel_register_access_fini(); + +out: + free(cmdname); + return ret; +} + diff --git a/tools/intel_reg_snapshot.c b/tools/intel_reg_snapshot.c new file mode 100644 index 00000000..83e76e5c --- /dev/null +++ b/tools/intel_reg_snapshot.c @@ -0,0 +1,48 @@ +/* + * 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 (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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Adam Jackson <ajax@redhat.com> + */ + +#include <unistd.h> +#include "intel_gpu_tools.h" + +int main(int argc, char** argv) +{ + struct pci_device *pci_dev; + uint32_t devid; + int mmio_bar; + + pci_dev = intel_get_pci_device(); + devid = pci_dev->device_id; + intel_get_mmio(pci_dev); + + if (IS_GEN2(devid)) + mmio_bar = 1; + else + mmio_bar = 0; + + write(1, mmio, pci_dev->regions[mmio_bar].size); + + return 0; +} diff --git a/tools/intel_reg_write.c b/tools/intel_reg_write.c new file mode 100644 index 00000000..dd636f65 --- /dev/null +++ b/tools/intel_reg_write.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 Gamari <bgamari.foss@gmail.com> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include "intel_gpu_tools.h" + +int main(int argc, char** argv) +{ + uint32_t reg, value; + volatile uint32_t *ptr; + + if (argc < 3) { + printf("Usage: %s addr value\n", argv[0]); + printf(" WARNING: This is dangerous to you and your system's health.\n"); + printf(" Only for use in debugging.\n"); + exit(1); + } + + intel_register_access_init(intel_get_pci_device(), 0); + sscanf(argv[1], "0x%x", ®); + sscanf(argv[2], "0x%x", &value); + ptr = (volatile uint32_t *)((volatile char *)mmio + reg); + + printf("Value before: 0x%X\n", *ptr); + *ptr = value; + printf("Value after: 0x%X\n", *ptr); + + intel_register_access_fini(); + return 0; +} + diff --git a/tools/intel_stepping.c b/tools/intel_stepping.c new file mode 100644 index 00000000..f6f15d1a --- /dev/null +++ b/tools/intel_stepping.c @@ -0,0 +1,294 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <pciaccess.h> +#include <err.h> +#include "intel_chipset.h" +#include "intel_gpu_tools.h" + +static void +print_clock(const char *name, int clock) { + if (clock == -1) + printf("%s clock: unknown", name); + else + printf("%s clock: %d Mhz", name, clock); +} + +static int +print_clock_info(struct pci_device *pci_dev) +{ + uint32_t devid = pci_dev->device_id; + uint16_t gcfgc; + + if (IS_GM45(devid)) { + int core_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0xf) { + case 8: + core_clock = 266; + break; + case 9: + core_clock = 320; + break; + case 11: + core_clock = 400; + break; + case 13: + core_clock = 533; + break; + } + print_clock("core", core_clock); + } else if (IS_965(devid) && IS_MOBILE(devid)) { + int render_clock = -1, sampler_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0xf) { + case 2: + render_clock = 250; sampler_clock = 267; + break; + case 3: + render_clock = 320; sampler_clock = 333; + break; + case 4: + render_clock = 400; sampler_clock = 444; + break; + case 5: + render_clock = 500; sampler_clock = 533; + break; + } + + print_clock("render", render_clock); + printf(" "); + print_clock("sampler", sampler_clock); + } else if (IS_945(devid) && IS_MOBILE(devid)) { + int render_clock = -1, display_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0x7) { + case 0: + render_clock = 166; + break; + case 1: + render_clock = 200; + break; + case 3: + render_clock = 250; + break; + case 5: + render_clock = 400; + break; + } + + switch (gcfgc & 0x70) { + case 0: + display_clock = 200; + break; + case 4: + display_clock = 320; + break; + } + if (gcfgc & (1 << 7)) + display_clock = 133; + + print_clock("render", render_clock); + printf(" "); + print_clock("display", display_clock); + } else if (IS_915(devid) && IS_MOBILE(devid)) { + int render_clock = -1, display_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0x7) { + case 0: + render_clock = 160; + break; + case 1: + render_clock = 190; + break; + case 4: + render_clock = 333; + break; + } + if (gcfgc & (1 << 13)) + render_clock = 133; + + switch (gcfgc & 0x70) { + case 0: + display_clock = 190; + break; + case 4: + display_clock = 333; + break; + } + if (gcfgc & (1 << 7)) + display_clock = 133; + + print_clock("render", render_clock); + printf(" "); + print_clock("display", display_clock); + } + + printf("\n"); + return -1; +} + +int main(int argc, char **argv) +{ + struct pci_device *dev, *bridge; + int error; + uint8_t stepping; + const char *step_desc = "??"; + + error = pci_system_init(); + if (error != 0) { + fprintf(stderr, "Couldn't initialize PCI system: %s\n", + strerror(error)); + exit(1); + } + + /* Grab the graphics card */ + dev = pci_device_find_by_slot(0, 0, 2, 0); + if (dev == NULL) + errx(1, "Couldn't find graphics card"); + + error = pci_device_probe(dev); + if (error != 0) { + fprintf(stderr, "Couldn't probe graphics card: %s\n", + strerror(error)); + exit(1); + } + + if (dev->vendor_id != 0x8086) + errx(1, "Graphics card is non-intel"); + + bridge = pci_device_find_by_slot(0, 0, 0, 0); + if (dev == NULL) + errx(1, "Couldn't bridge"); + + error = pci_device_cfg_read_u8(bridge, &stepping, 8); + if (error != 0) { + fprintf(stderr, "Couldn't read revision ID: %s\n", + strerror(error)); + exit(1); + } + + switch (dev->device_id) { + case PCI_CHIP_I915_G: + if (stepping < 0x04) + step_desc = "<B1"; + else if (stepping == 0x04) + step_desc = "B1"; + else if (stepping == 0x0e) + step_desc = "C2"; + else if (stepping > 0x0e) + step_desc = ">C2"; + else + step_desc = ">B1 <C2"; + break; + case PCI_CHIP_I915_GM: + if (stepping < 0x03) + step_desc = "<B1"; + else if (stepping == 0x03) + step_desc = "B1/C0"; + else if (stepping == 0x04) + step_desc = "C1/C2"; + else + step_desc = ">C2"; + break; + case PCI_CHIP_I945_GM: + if (stepping < 0x03) + step_desc = "<A3"; + else if (stepping == 0x03) + step_desc = "A3"; + else + step_desc = ">A3"; + break; + case PCI_CHIP_I965_G: + case PCI_CHIP_I965_Q: + if (stepping < 0x02) + step_desc = "<C1"; + else if (stepping == 0x02) + step_desc = "C1/C2"; + else + step_desc = ">C2"; + break; + case PCI_CHIP_I965_GM: + if (stepping < 0x03) + step_desc = "<C0"; + else if (stepping == 0x03) + step_desc = "C0"; + else + step_desc = ">C0"; + break; + case PCI_CHIP_I965_G_1: + if (stepping < 0x03) + step_desc = "<E0"; + else if (stepping == 0x03) + step_desc = "E0"; + else + step_desc = ">E0"; + break; + case PCI_CHIP_GM45_GM: + if (stepping < 0x07) + step_desc = "<B3"; + else if (stepping == 0x03) + step_desc = "B3"; + else + step_desc = ">B3"; + break; + case PCI_CHIP_G45_G: + case PCI_CHIP_Q45_G: + case PCI_CHIP_G41_G: + if (stepping < 0x02) + step_desc = "<A2"; + else if (stepping == 0x02) + step_desc = "A2"; + else if (stepping == 0x03) + step_desc = "A3"; + else + step_desc = ">A3"; + break; + } + + printf("Vendor: 0x%04x, Device: 0x%04x, Revision: 0x%02x (%s)\n", + dev->vendor_id, + dev->device_id, + stepping, + step_desc); + + print_clock_info(dev); + + return 0; +} |