summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2011-01-26 15:04:58 -0500
committerDave Airlie <airlied@redhat.com>2011-02-08 05:58:35 +1000
commit3b05824e9d5fa58fcba838b34fcabcb1ee6a1b89 (patch)
treee823452a0988908ea9758a79b8afdc0ccb2c5511
parent08c93b41a8119c99202be1962c83bf8da92b9ee8 (diff)
add radeonreg program
simple reg dumper for different families. radeonreg regs <set> <set> radeon - r128, r1xx-r4xx avivo - r5xx, rs600/690/740, r600, rv610/630/670 dce3 - rv620/635/770/710/730/740, rs780/880 dce4 - evergreen dce5 - ni Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--Makefile.am6
-rw-r--r--radeonreg.c422
2 files changed, 427 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 9915a16..8222acc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,7 +20,7 @@
AUTOMAKE_OPTIONS = foreign
-bin_PROGRAMS = radeontool avivotool
+bin_PROGRAMS = radeontool avivotool radeonreg
AM_CFLAGS = $(LIBPCIACCESS_CFLAGS)
@@ -28,6 +28,10 @@ radeontool_SOURCES = radeontool.c radeon_reg.h xf86i2c.h radeon.h radeon_chipinf
avivotool_SOURCES = avivotool.c atom.c xf86i2c.c atombios_tables.c \
atombios.h atom.h atom-bits.h radeon.h radeon_chipinfo_gen.h \
atom-types.h kernel-compat.h ObjectID.h atom-names.h
+radeonreg_SOURCES = radeonreg.c \
+ radeon.h radeon_chipinfo_gen.h \
+ kernel-compat.h
radeontool_LDADD = $(LIBPCIACCESS_LIBS)
avivotool_LDADD = $(LIBPCIACCESS_LIBS)
+radeonreg_LDADD = $(LIBPCIACCESS_LIBS)
diff --git a/radeonreg.c b/radeonreg.c
new file mode 100644
index 0000000..d9fc471
--- /dev/null
+++ b/radeonreg.c
@@ -0,0 +1,422 @@
+/*
+ * avivotool v0.1
+ * by Daniel Stone <daniel@fooishbar.org>
+ *
+ * based on:
+ * Radeontool v1.4
+ * by Frederick Dean <software@fdd.com>
+ *
+ * Copyright 2002-2004 Frederick Dean
+ * Use hereby granted under the zlib license.
+ *
+ * Warning: I do not have the Radeon documents, so this was engineered from
+ * the radeon_reg.h header file.
+ *
+ * USE RADEONTOOL AT YOUR OWN RISK
+ *
+ * Thanks to Deepak Chawla, Erno Kuusela, Rolf Offermanns, and Soos Peter
+ * for patches.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <fnmatch.h>
+#include <errno.h>
+#include <pciaccess.h>
+
+#include "radeon.h"
+#include "radeon_reg.h"
+
+int skip;
+
+/* *ctrl_mem is mapped to the actual device's memory mapped control area. */
+/* Not the address but what it points to is volatile. */
+struct pci_device *avivo_device = NULL;
+RADEONCardInfo *card_info = NULL;
+unsigned int ctrl_region, fb_region;
+unsigned char * volatile ctrl_mem;
+unsigned char * volatile fb_mem;
+
+
+static void fatal(char *why)
+{
+ fprintf(stderr, why);
+ pci_system_cleanup();
+
+}
+
+static void radeon_set(unsigned long offset, const char *name, unsigned int value)
+{
+
+ if (ctrl_mem == NULL)
+ fatal("internal error\n");
+
+#ifdef __powerpc__
+ __asm__ __volatile__ ("stwbrx %1,%2,%3\n\t"
+ "eieio"
+ : "=m" (*((volatile unsigned int *)ctrl_mem+offset))
+ : "r"(value), "b"(ctrl_mem), "r"(offset));
+#else
+ *(unsigned int * volatile)(ctrl_mem + offset) = value;
+#endif
+}
+
+static void radeon_set_indexed(unsigned long index_offset,
+ unsigned long data_offset, unsigned long offset,
+ const char *name, unsigned int value)
+{
+ radeon_set(index_offset, "index", offset);
+ radeon_set(data_offset, name, value);
+}
+
+static unsigned int radeon_get(unsigned long offset, const char *name)
+{
+ unsigned int value;
+
+ if (ctrl_mem == NULL)
+ fatal("internal error\n");
+
+#ifdef __powerpc__
+ __asm__ __volatile__ ("lwbrx %0,%1,%2\n\t"
+ "eieio"
+ : "=r" (value)
+ : "b" (ctrl_mem), "r"(offset),
+ "m" (*((volatile unsigned int *)ctrl_mem+offset)));
+#else
+ value = *(unsigned int * volatile)(ctrl_mem + offset);
+#endif
+
+ return value;
+}
+
+static unsigned int radeon_get_indexed(unsigned long index_offset,
+ unsigned long data_offset,
+ unsigned long offset, const char *name)
+{
+ radeon_set(index_offset, "index", offset);
+ return radeon_get(data_offset, name);
+}
+
+static unsigned int radeon_get_clk(unsigned long offset, const char *name)
+{
+ return radeon_get_indexed(RADEON_CLOCK_CNTL_INDEX,
+ RADEON_CLOCK_CNTL_DATA,
+ offset, name);
+}
+
+static void radeon_set_clk(unsigned long offset, const char *name,
+ unsigned int value)
+{
+ return radeon_set_indexed(RADEON_CLOCK_CNTL_INDEX, RADEON_CLOCK_CNTL_DATA,
+ offset | RADEON_PLL_WR_EN, name, value);
+}
+
+static unsigned int radeon_get_mc(unsigned long offset, const char *name)
+{
+ return radeon_get_indexed(AVIVO_MC_INDEX, AVIVO_MC_DATA,
+ offset | 0x007f0000, name);
+}
+
+static void radeon_set_mc(unsigned long offset, const char *name,
+ unsigned int value)
+{
+ return radeon_set_indexed(AVIVO_MC_INDEX, AVIVO_MC_DATA,
+ offset | 0x00ff0000, name, value);
+}
+
+static unsigned int radeon_get_pcie(unsigned long offset, const char *name)
+{
+ return radeon_get_indexed(0x30, 0x34, offset, name);
+}
+
+static void radeon_set_pcie(unsigned long offset, const char *name, unsigned int value)
+{
+ return radeon_set_indexed(0x30, 0x34, offset, name, value);
+}
+
+static void rs690_set_mc(unsigned long offset, const char *name, unsigned int value)
+{
+ return radeon_set_indexed(RS690_NB_MC_INDEX, RS690_NB_MC_DATA,
+ (offset & RS690_MC_INDEX_MASK) | RS690_MC_INDEX_WR_EN, name, value);
+}
+
+static unsigned int rs690_get_mc(unsigned long offset, const char *name)
+{
+ return radeon_get_indexed(RS690_NB_MC_INDEX, RS690_NB_MC_DATA, offset, name);
+}
+
+static void usage(void)
+{
+ printf("usage: radeonreg [options] [command]\n");
+ printf(" --skip=1 - use the second radeon card\n");
+ printf(" regs <set> - show a listing of some random registers\n");
+ printf(" regmatch <pattern> - show registers matching wildcard pattern\n");
+ printf(" regset <pattern> <value> - set registers matching wildcard pattern\n");
+ exit(-1);
+}
+
+#define GET_REG(r) radeon_get(r, #r)
+#define SET_REG(r, v) radeon_set(r, #r, v)
+
+#define GET_REG(r) radeon_get(r, #r)
+#define SHOW_REG(r) printf("%s\t%08x\n", #r, radeon_get(r, #r))
+#define SHOW_UNKNOWN_REG(r) { tmp = radeon_get(r, "byhand"); printf("%08lx\t%08x (%d)\n", r, tmp, tmp); }
+#define REG_TYPE_NAME(r) ((r == REG_TYPE_STATIC) ? "static" : ((r == REG_TYPE_SEMI_STATIC) ? "semi-static" : "random"))
+#define SHOW_STATIC_REG(r) { tmp = get_reg_type(r); printf("%s (%08lx)\t%s\n", get_reg_name(r, ""), r, REG_TYPE_NAME(tmp)); }
+#define SHOW_REG_DECIMAL(r) printf("%s\t%d (decimal)\n", #r, radeon_get(r, #r))
+#define SHOW_REG_BITS(r, ...) radeon_show_reg_bits(NULL, #r, 0, 0, r, __VA_ARGS__)
+#define SHOW_MC_REG(r) printf("%s\t%08x\n", #r, radeon_get_indexed(AVIVO_MC_INDEX, AVIVO_MC_DATA, (r | 0x007f0000), #r))
+#define SHOW_MC_REG_BITS(r, ...) radeon_show_reg_bits(NULL, AVIVO_MC_INDEX, AVIVO_MC_DATA, #r, (r | 0x007f0000), __VA_ARGS__)
+#define SHOW_PCIE_REG(r) printf("%s\t%08x\n", #r, radeon_get_indexed(0x30, 0x34, (r), #r))
+
+#define SHOW_UNK_MC_REG(r) printf("%02x\t%08x\n", r, radeon_get_indexed(AVIVO_MC_INDEX, AVIVO_MC_DATA, (r | 0x007f0000), #r))
+
+#define SHOW_UNK_CLK_REG(r) printf("%02x\t%08x\n", r, radeon_get_indexed(RADEON_CLOCK_CNTL_INDEX, RADEON_CLOCK_CNTL_DATA, (r), #r))
+
+void radeon_cmd_regs(const char *type)
+{
+ int show_all = (strcmp(type, "all") == 0);
+ int shut_up = 1;
+ int tmp; /* may be stomped at any moment. */
+ unsigned long i;
+
+ /* Dump all registers that we can read. */
+ if (strcmp(type, "radeon") == 0) {
+ for (i = 0x0000; i < 0x00fc; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0x0200; i < 0x060c; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0x0800; i < 0x0904; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0x0d00; i < 0x0d78; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0; i < 0x2f; i++)
+ SHOW_UNK_CLK_REG(i);
+ return;
+ }
+ if (strcmp(type, "avivo") == 0) {
+ for (i = 0x0000; i < 0x5b4; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0x5dfc; i < 0x7ff0; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0; i < 0x3f; i++)
+ SHOW_UNK_CLK_REG(i);
+ return;
+ }
+ if (strcmp(type, "dce3") == 0) {
+ for (i = 0x0000; i < 0x5bc; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0x5dfc; i < 0x8000; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ return;
+ }
+ if (strcmp(type, "dce4") == 0) {
+ for (i = 0x0000; i < 0x5e8; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0x5c6c; i < 0x7f64; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0x10000; i < 0x12f64; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ return;
+ }
+ if (strcmp(type, "dce5") == 0) {
+ for (i = 0x0000; i < 0x5e8; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0x5800; i < 0x7fa4; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ for (i = 0x10000; i < 0x12fa4; i += 4)
+ SHOW_UNKNOWN_REG(i);
+ return;
+ }
+}
+
+void radeon_reg_match(const char *pattern)
+{
+ int i;
+ unsigned long address;
+ unsigned int value;
+
+ if (pattern[0] == '0' && pattern[1] == 'x') {
+ address = strtol(&(pattern[2]), NULL, 16);
+ value = radeon_get(address, pattern);
+ printf("%s\t0x%08x (%d)\n", pattern, value, value);
+ }
+ else if (pattern[0] == 'M' && pattern[1] == 'C' && pattern[2] == ':') {
+ address = strtol(&(pattern[3]), NULL, 16);
+ value = radeon_get_mc(address, pattern);
+ printf("%s\t0x%08x (%d)\n", pattern, value, value);
+ }
+ else if (pattern[0] == 'C' && pattern[1] == 'L' && pattern[2] == ':') {
+ address = strtol(&(pattern[3]), NULL, 16);
+ value = radeon_get_clk(address, pattern);
+ printf("%s\t0x%08x (%d)\n", pattern, value, value);
+ }
+ else if (pattern[0] == 'P' && pattern[1] == 'C' && pattern[2] == ':') {
+ address = strtol(&(pattern[3]), NULL, 16);
+ value = radeon_get_pcie(address, pattern);
+ printf("%s\t0x%08x (%d)\n", pattern, value, value);
+ }
+}
+
+void set_reg(const char *name, const char *type, unsigned long address,
+ unsigned int value,
+ unsigned int (*get)(unsigned long, const char *),
+ void (*set)(unsigned long, const char *, unsigned int))
+{
+ unsigned int readback;
+
+ readback = get(address, name);
+ printf("OLD: %s (%s%04lx)\t0x%08x (%d)\n", name, type, address,
+ readback, readback);
+ set(address, name, value);
+ readback = get(address, name);
+ printf("NEW: %s (%s%04lx)\t0x%08x (%d)\n", name, type, address,
+ readback, readback);
+}
+
+void radeon_reg_set(const char *inname, unsigned int value)
+{
+ int i;
+ unsigned long address;
+
+ if (inname[0] == '0' && inname[1] == 'x') {
+ address = strtol(&(inname[2]), NULL, 16);
+ set_reg(inname, "", address, value, radeon_get, radeon_set);
+ }
+ else if (inname[0] == 'M' && inname[1] == 'C' && inname[2] == ':') {
+ address = strtol(&(inname[3]), NULL, 16);
+ set_reg(inname, "MC: ", address, value, radeon_get_mc, radeon_set_mc);
+ }
+ else if (inname[0] == 'C' && inname[1] == 'L' && inname[2] == ':') {
+ address = strtol(&(inname[3]), NULL, 16);
+ set_reg(inname, "CL: ", address, value, radeon_get_clk, radeon_set_clk);
+ }
+ else if (inname[0] == 'P' && inname[1] == 'C' && inname[2] == ':') {
+ address = strtol(&(inname[3]), NULL, 16);
+ set_reg(inname, "PCIE: ", address, value, radeon_get_pcie, radeon_set_pcie);
+ }
+}
+
+/* Find and map the buffers. */
+static int map_radeon_mem(void)
+{
+#if 0
+ struct pci_id_match match;
+#else
+ struct pci_slot_match match;
+#endif
+ struct pci_device_iterator *iter;
+ struct pci_device *device;
+ int i = 0;
+
+ if (pci_system_init() != 0)
+ fatal("failed to initialise libpciaccess\n");
+
+#if 0
+ match.vendor_id = 0x1002;
+ match.device_id = PCI_MATCH_ANY;
+ match.subvendor_id = PCI_MATCH_ANY;
+ match.subdevice_id = PCI_MATCH_ANY;
+ match.device_class = (0x03 << 16);
+ match.device_class_mask = 0x00ff0000;
+ match.match_data = 0;
+ iter = pci_id_match_iterator_create(&match);
+#else
+ match.domain = PCI_MATCH_ANY;
+ match.bus = PCI_MATCH_ANY;
+ match.dev = PCI_MATCH_ANY;
+
+ match.func = 0;
+ match.match_data = 0;
+ iter = pci_slot_match_iterator_create(&match);
+#endif
+
+ while ((device = pci_device_next(iter))) {
+ pci_device_probe(device);
+ if (device->vendor_id == 0x1002 &&
+ (((device->device_class & 0x00ffff00) == 0x00030000) ||
+ ((device->device_class & 0x00ffff00) == 0x00038000))) {
+ for (i = 0; i < sizeof(RADEONCards) / sizeof(RADEONCardInfo); i++) {
+ if (RADEONCards[i].pci_device_id == device->device_id)
+ card_info = &RADEONCards[i];
+ }
+
+ fb_region = 0;
+ ctrl_region = 2;
+ avivo_device = device;
+ if(skip-- == 0) {
+ break;
+ }
+ }
+ }
+
+ if (!avivo_device){
+ printf("cannot find Radeon device\n");
+ return -1;
+ }
+
+ if (pci_device_map_region(avivo_device, ctrl_region, 1) != 0)
+ fatal("mapping ctrl region\n");
+ ctrl_mem = avivo_device->regions[ctrl_region].memory;
+
+ if (pci_device_map_region(avivo_device, fb_region, 1) == 0)
+ fb_mem = avivo_device->regions[fb_region].memory;
+ else
+ fb_mem = NULL;
+
+ pci_iterator_destroy(iter);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ if (argc == 1)
+ usage();
+
+ skip = 0;
+ if (argc > 1 && strncmp(argv[1], "--skip=", 7) == 0) {
+ skip = atoi(argv[1] + 7);
+ argv++;
+ argc--;
+ }
+
+ ret = map_radeon_mem();
+ if (ret!=0)
+ fatal("Unable to see card\n");
+
+ if (argc == 2) {
+ if (strcmp(argv[1], "regs") == 0) {
+ radeon_cmd_regs("default");
+ return 0;
+ }
+ } else if (argc == 3) {
+ if (strcmp(argv[1], "regmatch") == 0) {
+ radeon_reg_match(argv[2]);
+ return 0;
+ } else if (strcmp(argv[1], "regs") == 0) {
+ radeon_cmd_regs(argv[2]);
+ return 0;
+ }
+
+ } else if (argc == 4) {
+ if (strcmp(argv[1], "regset") == 0) {
+ radeon_reg_set(argv[2], strtoul(argv[3], NULL, 0));
+ return 0;
+ }
+ }
+
+ usage();
+
+ pci_system_cleanup();
+
+ return 1;
+}