/* * avivotool v0.1 * by Daniel Stone * * based on: * Radeontool v1.4 * by Frederick Dean * * 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 #include #include #include #include #include #include #include #include #include #include #include #include "radeon.h" #include "radeon_reg.h" #ifdef __powerpc__ #ifdef _LITTLE_ENDIAN #define ppc64le #else #define ppcBE #endif #endif 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. */ RADEONCardInfo *card_info = NULL; unsigned char * volatile ctrl_mem; unsigned char * volatile fb_mem; static void die(const char *why) { fprintf(stderr, "fatal error: %s\n", why); pci_system_cleanup(); exit(-1); } static void die_error(int err, const char *why) { fprintf(stderr, "fatal error: %s: %s\n", why, strerror(err)); pci_system_cleanup(); exit(-1); } #ifdef ppc64le #define LOADX "lwzx" #define STOREX "stwx" #elif defined(ppcBE) #define LOADX "lwbrx" #define STOREX "stwbrx" #else #define LOADX #define STOREX #endif static void radeon_set(unsigned long offset, const char *name, unsigned int value) { if (ctrl_mem == NULL) die("internal error"); #ifdef __powerpc__ __asm__ __volatile__ (STOREX " %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) die("internal error"); #ifdef __powerpc__ __asm__ __volatile__ (LOADX " %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 - show a listing of some random registers\n"); printf(" regmatch - show registers matching wildcard pattern\n"); printf(" regset - 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)) static void radeon_show_radeon_display_regs(const char *type) { int tmp; /* may be stomped at any moment. */ unsigned long i; 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); } static void radeon_show_avivo_display_regs(const char *type) { int tmp; /* may be stomped at any moment. */ unsigned long i; 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); } static void radeon_show_dce3_display_regs(const char *type) { int tmp; /* may be stomped at any moment. */ unsigned long i; for (i = 0x0000; i < 0x5bc; i += 4) SHOW_UNKNOWN_REG(i); for (i = 0x5dfc; i < 0x8000; i += 4) SHOW_UNKNOWN_REG(i); } static void radeon_show_dce4_display_regs(const char *type) { int tmp; /* may be stomped at any moment. */ unsigned long i; 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); } static void radeon_show_dce5_display_regs(const char *type) { int tmp; /* may be stomped at any moment. */ unsigned long i; 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); } static void radeon_show_dce6_display_regs(const char *type) { int tmp; /* may be stomped at any moment. */ unsigned long i; for (i = 0x0000; i < 0x5e8; i += 4) SHOW_UNKNOWN_REG(i); for (i = 0x5800; i < 0x7fb0; i += 4) SHOW_UNKNOWN_REG(i); for (i = 0x10000; i < 0x12fb0; i += 4) SHOW_UNKNOWN_REG(i); } static void radeon_show_dce8_display_regs(const char *type) { int tmp; /* may be stomped at any moment. */ unsigned long i; for (i = 0x0000; i < 0x5e4; i += 4) SHOW_UNKNOWN_REG(i); for (i = 0x5800; i < 0x7fb0; i += 4) SHOW_UNKNOWN_REG(i); for (i = 0x10000; i < 0x12fb0; i += 4) SHOW_UNKNOWN_REG(i); } void radeon_cmd_regs(const char *type) { /* Dump all registers that we can read. */ if (strcmp(type, "radeon") == 0) { radeon_show_radeon_display_regs(type); return; } if (strcmp(type, "avivo") == 0) { radeon_show_avivo_display_regs(type); return; } if (strcmp(type, "dce3") == 0) { radeon_show_dce3_display_regs(type); return; } if (strcmp(type, "dce4") == 0) { radeon_show_dce4_display_regs(type); return; } if (strcmp(type, "dce5") == 0) { radeon_show_dce5_display_regs(type); return; } if (strcmp(type, "dce6") == 0) { radeon_show_dce6_display_regs(type); return; } if (strcmp(type, "dce8") == 0) { radeon_show_dce8_display_regs(type); return; } if (strcmp(type, "all") == 0) { if (IS_DISPLAY_RADEON(card_info)) radeon_show_radeon_display_regs(type); else if (IS_DISPLAY_AVIVO(card_info)) radeon_show_avivo_display_regs(type); else if (IS_DISPLAY_DCE3(card_info)) radeon_show_dce3_display_regs(type); else if (IS_DISPLAY_DCE4(card_info)) radeon_show_dce4_display_regs(type); else if (IS_DISPLAY_DCE5(card_info)) radeon_show_dce5_display_regs(type); else if (IS_DISPLAY_DCE6(card_info)) radeon_show_dce6_display_regs(type); else if (IS_DISPLAY_DCE8(card_info)) radeon_show_dce8_display_regs(type); else printf("unknown chipset, specify the regs to dump\n"); 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; pciaddr_t fb_base, fb_size, ctrl_base, ctrl_size; int i = 0, ret; ret = pci_system_init(); if (ret) die_error(ret, "failed to initialise libpciaccess"); #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) continue; if ((device->device_class & 0x00ffff00) != 0x00030000 && (device->device_class & 0x00ffff00) != 0x00038000) continue; if (skip--) continue; break; } if (!device) { printf("cannot find Radeon device\n"); return -1; } for (i = 0; i < sizeof(RADEONCards) / sizeof(RADEONCardInfo); i++) { if (RADEONCards[i].pci_device_id == device->device_id) card_info = &RADEONCards[i]; } if (card_info->chip_family < CHIP_FAMILY_BONAIRE) { ctrl_base = device->regions[2].base_addr; ctrl_size = device->regions[2].size; } else { ctrl_base = device->regions[5].base_addr; ctrl_size = device->regions[5].size; } if (!ctrl_size) die("missing ctrl region"); ret = pci_device_map_range(device, ctrl_base, ctrl_size, PCI_DEV_MAP_FLAG_WRITABLE, (void **) &ctrl_mem); if (ret) die_error(ret, "cannot map ctrl region"); fb_base = device->regions[0].base_addr; fb_size = device->regions[0].size; if (!fb_size || pci_device_map_range(device, fb_base, fb_size, PCI_DEV_MAP_FLAG_WRITABLE, (void **) &fb_mem)) 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) die("Unable to see card"); 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; }