diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2011-01-26 15:04:58 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-02-08 05:58:35 +1000 |
commit | 3b05824e9d5fa58fcba838b34fcabcb1ee6a1b89 (patch) | |
tree | e823452a0988908ea9758a79b8afdc0ccb2c5511 | |
parent | 08c93b41a8119c99202be1962c83bf8da92b9ee8 (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.am | 6 | ||||
-rw-r--r-- | radeonreg.c | 422 |
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; +} |