diff options
author | Michael Cree <mcree@orcon.net.nz> | 2009-03-18 22:22:18 +1300 |
---|---|---|
committer | Matthias Hopf <mhopf@suse.de> | 2009-04-23 17:22:24 +0200 |
commit | 87ba9c2e81f7ab9070d98ca186e63facaf6cf41e (patch) | |
tree | fd67a726c551ee12c82c00b9f406ecf483da635c /utils | |
parent | 9ad3554cd83654c2f2cff1dc29d6af9604b514a3 (diff) |
Added code to use libpciaccess and access PCI ROM
Uses libpciaccess if XSERVER_LIBPCIACCESS defined.
New features:
Can read BIOS from PCI ROM if unposted when using libpciaccess.
New options -e (enable PCI card) and -r (use PCI ROM not VBIOS)
Diffstat (limited to 'utils')
-rw-r--r-- | utils/conntest/rhd_conntest.c | 368 |
1 files changed, 340 insertions, 28 deletions
diff --git a/utils/conntest/rhd_conntest.c b/utils/conntest/rhd_conntest.c index 9e9a595..52f8d2b 100644 --- a/utils/conntest/rhd_conntest.c +++ b/utils/conntest/rhd_conntest.c @@ -35,7 +35,6 @@ #include <errno.h> #include <string.h> #include <sys/mman.h> -#include <pci/pci.h> #include <unistd.h> #include <stdlib.h> @@ -44,6 +43,12 @@ #endif #include "git_version.h" +#ifdef XSERVER_LIBPCIACCESS +#include <pciaccess.h> +#else +#include <pci/pci.h> +#endif + #ifndef ULONG typedef unsigned int ULONG; # define ULONG ULONG @@ -79,6 +84,26 @@ typedef unsigned int CARD32; /* Some register names */ enum { + /* Needed for enable PCI ROM read */ + BUS_CNTL = 0x4C, /* (RW) */ + GPIOPAD_MASK = 0x198, /* (RW) */ + GPIOPAD_A = 0x19C, /* (RW) */ + GPIOPAD_EN = 0x1A0, /* (RW) */ + VIPH_CONTROL = 0xC40, /* (RW) */ + SEPROM_CNTL1 = 0x1C0, /* (RW) */ + + ROM_CNTL = 0x1600, + GENERAL_PWRMGT = 0x0618, + LOW_VID_LOWER_GPIO_CNTL = 0x0724, + MEDIUM_VID_LOWER_GPIO_CNTL = 0x0720, + HIGH_VID_LOWER_GPIO_CNTL = 0x071C, + CTXSW_VID_LOWER_GPIO_CNTL = 0x0718, + LOWER_GPIO_ENABLE = 0x0710, + + VGA_RENDER_CONTROL = 0x0300, + D1VGA_CONTROL = 0x0330, + D2VGA_CONTROL = 0x0338, + /* DAC A */ DACA_ENABLE = 0x7800, DACA_SOURCE_SELECT = 0x7804, @@ -256,6 +281,21 @@ typedef enum dacOutput { DAC_COMPONENT } dacOutput; +/* Some defines needed for getting access to unposted BIOS */ + +#define SCK_PRESCALE (0xff << 24) +#define VIPH_EN (1 << 21) +#define BIOS_ROM_DIS (1 << 2) +#define D1VGA_MODE_ENABLE (1 << 0) +#define D1VGA_TIMING_SELECT (1 << 8) +#define D2VGA_MODE_ENABLE (1 << 0) +#define D2VGA_TIMING_SELECT (1 << 8) +#define VGA_VSTATUS_CNTL (0x3 << 16) +#define SCK_OVERWRITE (1 << 1) +#define SCK_PRESCALE_CRYSTAL_CLK_SHIFT 28 +#define OPEN_DRAIN_PADS (1 << 11) + + /* for RHD_R500/R600/RS690/RV620 */ chipType ChipType; @@ -509,6 +549,8 @@ dprint(unsigned char *start, unsigned long size) /* * */ +#ifndef XSERVER_LIBPCIACCESS +/* Only for libpci use */ static struct pci_dev * DeviceLocate(struct pci_dev *devices, int bus, int dev, int func) { @@ -520,12 +562,17 @@ DeviceLocate(struct pci_dev *devices, int bus, int dev, int func) return device; return NULL; } +#endif /* * */ static struct RHDDevice * +#ifdef XSERVER_LIBPCIACCESS +DeviceMatch(struct pci_device *device) +#else DeviceMatch(struct pci_dev *device) +#endif { int i; @@ -540,6 +587,8 @@ DeviceMatch(struct pci_dev *device) /* * */ +#ifndef XSERVER_LIBPCIACCESS +/* Only for libpci use */ static void * MapBar(struct pci_dev *device, int ioBar, int devMem) { @@ -561,6 +610,7 @@ MapBar(struct pci_dev *device, int ioBar, int devMem) return map; } +#endif /* * @@ -2375,6 +2425,129 @@ FreeVBIOS(unsigned char *rombase, int size) munmap(rombase,size); } + +#ifdef XSERVER_LIBPCIACCESS + +/* Copy BIOS from PCI ROM into memory buffer */ +unsigned char * +GetBIOS_from_PCI(struct RHDDevice *rhdDevice, struct pci_device *dev, void *io, int *size) +{ + unsigned char *rombase = NULL; + int errnum; + + CARD32 save_seprom_cntl1 = 0, + save_gpiopad_a, save_gpiopad_en, save_gpiopad_mask, + save_viph_cntl, + save_bus_cntl, + save_d1vga_control, save_d2vga_control, save_vga_render_control, + save_rom_cntl = 0, + save_gen_pwrmgt = 0, + save_low_vid_lower_gpio_cntl = 0, save_med_vid_lower_gpio_cntl = 0, + save_high_vid_lower_gpio_cntl = 0, save_ctxsw_vid_lower_gpio_cntl = 0, + save_lower_gpio_en = 0; + + /* We have to enable BIOS on an unposted card. But first we save the + state. Much of this code pinched from RHDReadPCIBios() in + rhd_driver.c */ + + if (rhdDevice->type < RHD_R600) + save_seprom_cntl1 = RegRead(io, SEPROM_CNTL1); + save_gpiopad_en = RegRead(io, GPIOPAD_EN); + save_gpiopad_a = RegRead(io, GPIOPAD_A); + save_gpiopad_mask = RegRead(io, GPIOPAD_MASK); + save_viph_cntl = RegRead(io, VIPH_CONTROL); + save_bus_cntl = RegRead(io, BUS_CNTL); + save_d1vga_control = RegRead(io, D1VGA_CONTROL); + save_d2vga_control = RegRead(io, D2VGA_CONTROL); + save_vga_render_control = RegRead(io, VGA_RENDER_CONTROL); + if (rhdDevice->type >= RHD_R600) { + save_rom_cntl = RegRead(io, ROM_CNTL); + save_gen_pwrmgt = RegRead(io, GENERAL_PWRMGT); + save_low_vid_lower_gpio_cntl = RegRead(io, LOW_VID_LOWER_GPIO_CNTL); + save_med_vid_lower_gpio_cntl = RegRead(io, MEDIUM_VID_LOWER_GPIO_CNTL); + save_high_vid_lower_gpio_cntl = RegRead(io, HIGH_VID_LOWER_GPIO_CNTL); + save_ctxsw_vid_lower_gpio_cntl = RegRead(io, CTXSW_VID_LOWER_GPIO_CNTL); + save_lower_gpio_en = RegRead(io, LOWER_GPIO_ENABLE); + } + + /* Set SPI ROM prescale value to change the SCK period */ + if (rhdDevice->type < RHD_R600) + RegMask(io, SEPROM_CNTL1, 0x0C << 24, SCK_PRESCALE); + /* Let chip control GPIO pads - this is the default state after power up */ + RegWrite(io, GPIOPAD_EN, 0); + RegWrite(io, GPIOPAD_A, 0); + /* Put GPIO pads in read mode */ + RegWrite(io, GPIOPAD_MASK, 0); + /* Disable VIP Host port */ + RegMask(io, VIPH_CONTROL, 0, VIPH_EN); + /* Enable BIOS ROM */ + RegMask(io, BUS_CNTL, 0, BIOS_ROM_DIS); + /* Disable VGA and select extended timings */ + RegMask(io, D1VGA_CONTROL, 0, + D1VGA_MODE_ENABLE | D1VGA_TIMING_SELECT); + RegMask(io, D2VGA_CONTROL, 0, + D2VGA_MODE_ENABLE | D2VGA_TIMING_SELECT); + RegMask(io, VGA_RENDER_CONTROL, 0, VGA_VSTATUS_CNTL); + if (rhdDevice->type >= RHD_R600) { + RegMask(io, ROM_CNTL, SCK_OVERWRITE + | 1 << SCK_PRESCALE_CRYSTAL_CLK_SHIFT, + SCK_OVERWRITE + | 1 << SCK_PRESCALE_CRYSTAL_CLK_SHIFT); + RegMask(io, GENERAL_PWRMGT, 0, OPEN_DRAIN_PADS); + RegMask(io, LOW_VID_LOWER_GPIO_CNTL, 0, 0x400); + RegMask(io, MEDIUM_VID_LOWER_GPIO_CNTL, 0, 0x400); + RegMask(io, HIGH_VID_LOWER_GPIO_CNTL, 0, 0x400); + RegMask(io, CTXSW_VID_LOWER_GPIO_CNTL, 0, 0x400); + RegMask(io, LOWER_GPIO_ENABLE, 0x400, 0x400); + } + + /* Read the ROM */ + + *size = (dev->rom_size > 0) ? dev->rom_size : 0x20000; + + rombase = malloc((size_t)*size); + + if ((errnum = pci_device_read_rom(dev, rombase))) { + fprintf(stderr,"Attempt to read ROM from PCI failed: %s.\n", + strerror(errnum)); + free(rombase); + rombase = NULL; + } + + /* Restore the state prior to being called */ + + if (rhdDevice->type < RHD_R600) + RegWrite(io, SEPROM_CNTL1, save_seprom_cntl1); + RegWrite(io, GPIOPAD_EN, save_gpiopad_en); + RegWrite(io, GPIOPAD_A, save_gpiopad_a); + RegWrite(io, GPIOPAD_MASK, save_gpiopad_mask); + RegWrite(io, VIPH_CONTROL, save_viph_cntl); + RegWrite(io, BUS_CNTL, save_bus_cntl); + RegWrite(io, D1VGA_CONTROL, save_d1vga_control); + RegWrite(io, D2VGA_CONTROL, save_d2vga_control); + RegWrite(io, VGA_RENDER_CONTROL, save_vga_render_control); + if (rhdDevice->type >= RHD_R600) { + RegWrite(io, ROM_CNTL, save_rom_cntl); + RegWrite(io, GENERAL_PWRMGT, save_gen_pwrmgt); + RegWrite(io, LOW_VID_LOWER_GPIO_CNTL, save_low_vid_lower_gpio_cntl); + RegWrite(io, MEDIUM_VID_LOWER_GPIO_CNTL, save_med_vid_lower_gpio_cntl); + RegWrite(io, HIGH_VID_LOWER_GPIO_CNTL, save_high_vid_lower_gpio_cntl); + RegWrite(io, CTXSW_VID_LOWER_GPIO_CNTL, save_ctxsw_vid_lower_gpio_cntl); + RegWrite(io, LOWER_GPIO_ENABLE, save_lower_gpio_en); + } + + return rombase; +} + + + +void FreeBIOS_from_PCI(unsigned char *rombase) +{ + if (rombase) free(rombase); +} +#endif + + /* * */ @@ -2478,8 +2651,12 @@ print_help(const char* progname, const char* message, const char* msgarg) fprintf(stderr, "%s %s\n", message, msgarg); fprintf(stderr, "Usage: %s [options] PCI-tag\n" " Options: -d: dumpBios\n" +#ifdef XSERVER_LIBPCIACCESS + " -e: enable pci card (not normally needed)\n" + " -r: only attempt BIOS read via PCI ROM\n" +#endif " -s: scanDDCBus\n" - " -x num: dump num bytes from available i2c channels\n" + " -x num: dump num bytes from available i2c channels\n" " PCI-tag: bus:dev.func\n\n", progname); } @@ -2615,28 +2792,48 @@ InterpretATOMBIOS(unsigned char *base) int main(int argc, char *argv[]) { +#ifdef XSERVER_LIBPCIACCESS + struct pci_device *device = NULL; + int enable_device; +#else struct pci_dev *device = NULL; struct pci_access *pciAccess; - struct RHDDevice *rhdDevice = NULL; int devMem; + int saved_errno; +#endif + struct RHDDevice *rhdDevice = NULL; void *io; int bus, dev, func; int ret; - int saved_errno; Bool deviceSet = FALSE; Bool dumpBios = FALSE, scanDDCBus = FALSE; unsigned long DumpI2CData = 0; int i; unsigned char *rombase; int size; + int using_vbios; printf("%s: v%s, %s\n", "rhd_conntest", PACKAGE_VERSION, GIT_MESSAGE); +#ifdef XSERVER_LIBPCIACCESS + /* Initialise pciaccess */ + if ((i = pci_system_init())) { + fprintf(stderr, "ERROR: pciaccess failed to initialise PCI bus" + " (error %d)\n", i); + return 1; + } + /* Default actions */ + enable_device = FALSE; + using_vbios = TRUE; +#else /* init libpci */ pciAccess = pci_alloc(); pci_init(pciAccess); pci_scan_bus(pciAccess); + /* Default action */ + using_vbios = TRUE; +#endif if (argc < 2) { print_help(argv[0], "Missing argument: please provide a PCI tag\n", @@ -2645,6 +2842,13 @@ main(int argc, char *argv[]) } for (i = 1; i < argc; i++) { +#ifdef XSERVER_LIBPCIACCESS + if (!strncmp("-e", argv[i], 3)) { + enable_device = TRUE; + }else if (!strncmp("-r", argv[i], 3)) { + using_vbios = FALSE; + }else +#endif if (!strncmp("-d",argv[i],3)) { dumpBios = TRUE; } else if (!strncmp("-s",argv[i],3)) { @@ -2681,14 +2885,33 @@ main(int argc, char *argv[]) } } + if (!using_vbios & !deviceSet) { + /* Not technically an error, but only a right plonker would specify + this combination of command line options. */ + printf("What?!! You want me to do nothing!\n" + "Specify a PCI tag and/or don't specify '-r' for some action.\n"); + return 0; + } + if (deviceSet) { - /* find our toy */ +#ifdef XSERVER_LIBPCIACCESS + /* Find the toy using pciaccess */ + if ((device = pci_device_find_by_slot(0, bus, dev, func)) == NULL) { + fprintf(stderr, "ERROR: Unable to find PCI device at %02X:%02X.%02X.\n", + bus, dev, func); + return 1; + } + if (enable_device) + pci_device_enable(device); +#else + /* find our toy using pci */ device = DeviceLocate(pciAccess->devices, bus, dev, func); if (!device) { fprintf(stderr, "Unable to find PCI device at %02X:%02X.%02X.\n", bus, dev, func); return 1; } +#endif rhdDevice = DeviceMatch(device); if (!rhdDevice) { @@ -2697,43 +2920,82 @@ main(int argc, char *argv[]) device->vendor_id, device->device_id, bus, dev, func); return 1; } - } - rombase = GetVBIOS(&size); - if (!rombase) { - fprintf(stderr, "Cannot get VBIOS. Are we root?\n"); - } else - if (!InterpretATOMBIOS(rombase)) { - fprintf(stderr, "Cannot analyze AtomBIOS\n"); - return 1; +#ifdef XSERVER_LIBPCIACCESS + printf("Found card: %s - %s\n", + pci_device_get_vendor_name(device), + pci_device_get_device_name(device)); +#endif } - if (dumpBios && rombase) { - char name[1024] = "posted.vga.rom"; - - if (deviceSet) { - snprintf(name, 1023, "%04X.%04X.%04X.vga.rom", - device->device_id, - pci_read_word(device, PCI_SUBSYSTEM_VENDOR_ID), - pci_read_word(device, PCI_SUBSYSTEM_ID)); + if (using_vbios) { + /* Attempt to read BIOS from legacy VBIOS. */ + rombase = GetVBIOS(&size); + if (!rombase) { + printf("Cannot get VBIOS. Are we root?\n"); + }else{ + if (!InterpretATOMBIOS(rombase)) { + printf("Cannot analyze AtomBIOS from VBIOS\n"); + rombase = NULL; + } } - WriteToFile(name, rombase, size); + if (dumpBios && rombase) { + char name[1024] = "posted.vga.rom"; + + if (deviceSet) { +#ifdef XSERVER_LIBPCIACCESS + snprintf(name, 1023, "%04X.%04X.%04X.vga.rom", + device->device_id, device->subvendor_id, device->subdevice_id); +#else + snprintf(name, 1023, "%04X.%04X.%04X.vga.rom", + device->device_id, + pci_read_word(device, PCI_SUBSYSTEM_VENDOR_ID), + pci_read_word(device, PCI_SUBSYSTEM_ID)); +#endif + } + WriteToFile(name, rombase, size); + } + }else{ + /* We ain't goin' to read VBIOS - flag that */ + rombase = NULL; } - if (!deviceSet) + /* We reuse the flag using_vbios now to indicate whether we successfully + read the VBIOS (rombase is not suitable for the purpose) */ + using_vbios = rombase ? 1 : 0; + + if (!deviceSet) { + if (! using_vbios) { + fprintf(stderr, "ERROR: Failed to read VBIOS.\n"); + return 1; + } return 0; + } if (rhdDevice->bar > 5) { - fprintf(stderr, "Program error: No acceptable BAR defined for this device.\n"); + fprintf(stderr, "ERROR: No acceptable PCI BAR defined for this device.\n"); return 1; } - printf("Checking connectors on 0x%04X, 0x%04X, 0x%04X (@%02X:%02X:%02X):\n", - device->device_id, pci_read_word(device, PCI_SUBSYSTEM_VENDOR_ID), - pci_read_word(device, PCI_SUBSYSTEM_ID), - device->bus, device->dev, device->func); + /* Map into CPU memory space the required PCI memory */ + +#ifdef XSERVER_LIBPCIACCESS + pci_device_probe(device); + if (device->regions[rhdDevice->bar].base_addr == 0) { + fprintf(stderr, "ERROR: Failed to find required resource on PCI card.\n"); + return 1; + } + + if ((i = pci_device_map_range(device,device->regions[rhdDevice->bar].base_addr, + device->regions[rhdDevice->bar].size, + PCI_DEV_MAP_FLAG_WRITABLE, &io))) { + fprintf(stderr, "ERROR: Couldn't map IO memory: %s.\n", strerror(i)); + return i; + } + +#else /* make sure we can actually read DEV_MEM before we do anything else */ devMem = open(DEV_MEM, O_RDWR); if (devMem < 0) { @@ -2749,6 +3011,45 @@ main(int argc, char *argv[]) strerror(saved_errno)); return 1; } +#endif + +#ifdef XSERVER_LIBPCIACCESS + /* Attempt to get unposted BIOS if failed before */ + + if (! using_vbios) { + printf("Trying to get BIOS from PCI ROM...\n"); + + if ((rombase = GetBIOS_from_PCI(rhdDevice, device, io, &size)) == NULL) { + fprintf(stderr,"ERROR: Fat lot of use that was -- can't read BIOS image\n"); + return 1; + } + + if (!InterpretATOMBIOS(rombase)) { + fprintf(stderr, "ERROR: Cannot analyze AtomBIOS from PCI ROM\n"); + return 1; + } + + if (dumpBios && rombase) { + char name[1024]; + + snprintf(name, 1023, "%04X.%04X.%04X.vga.rom", + device->device_id, device->subvendor_id, device->subdevice_id); + WriteToFile(name, rombase, size); + } + } +#endif + + +#ifdef XSERVER_LIBPCIACCESS + printf("Checking connectors on 0x%04X, 0x%04X, 0x%04X (@%02X:%02X:%02X):\n", + device->device_id, device->subvendor_id, device->subdevice_id, + device->bus, device->dev, device->func); +#else + printf("Checking connectors on 0x%04X, 0x%04X, 0x%04X (@%02X:%02X:%02X):\n", + device->device_id, pci_read_word(device, PCI_SUBSYSTEM_VENDOR_ID), + pci_read_word(device, PCI_SUBSYSTEM_ID), + device->bus, device->dev, device->func); +#endif ChipType = rhdDevice->type; @@ -2760,7 +3061,18 @@ main(int argc, char *argv[]) if (scanDDCBus || DumpI2CData) DDCScanBus(io, DumpI2CData); +#ifdef XSERVER_LIBPCIACCESS + if (using_vbios) { + FreeVBIOS(rombase, size); + }else{ + FreeBIOS_from_PCI(rombase); + } + + pci_device_unmap_range(device, io, device->regions[rhdDevice->bar].size); + pci_system_cleanup(); +#else FreeVBIOS(rombase, size); +#endif return 0; } |