 
/* 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 <unistd.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <fnmatch.h>
#include <pciaccess.h>

#include "radeon_reg.h"

int debug = 0;
int skip = 0;

/* *radeon_cntl_mem is mapped to the actual device's memory mapped control area. */
/* Not the address but what it points to is volatile. */
unsigned char * volatile radeon_cntl_mem;
unsigned char * volatile fb_mem;
unsigned char * volatile ctrl_mem;
static void radeon_rom_legacy_mmio_table(unsigned char *bios, int offset);
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);
}

static unsigned int radeon_get(unsigned long offset, const char *name)
{
    unsigned int value;
    if(debug) 
        printf("reading %s (%lx) is ",name,offset);
    assert(radeon_cntl_mem);
#ifdef __powerpc__
    __asm__ __volatile__ ("lwbrx %0,%1,%2\n\t"
			  "eieio"
			  : "=r" (value)
			  : "b" (radeon_cntl_mem), "r"(offset),
			  "m" (*((volatile unsigned int *)radeon_cntl_mem+offset)));
#else
    value = *(unsigned int * volatile)(radeon_cntl_mem+offset);  
#endif
    if(debug) 
        printf("%08x\n",value);
    return value;
}
static void radeon_set(unsigned long offset, const char *name, unsigned int value)
{
    if(debug) 
        printf("writing %s (%lx) -> %08x\n",name,offset,value);
    assert(radeon_cntl_mem);
#ifdef __powerpc__
    __asm__ __volatile__ ("stwbrx %1,%2,%3\n\t"
			  "eieio"
			  : "=m" (*((volatile unsigned int *)radeon_cntl_mem+offset))
			  : "r"(value), "b"(radeon_cntl_mem), "r"(offset));
#else
    *(unsigned int * volatile)(radeon_cntl_mem+offset) = value;  
#endif
}

static unsigned int radeon_get_indexed(unsigned long index_offset,
                                       unsigned long data_offset,
                                       unsigned long offset,
				       const char *name,
				       unsigned long index_mask)
{
    unsigned int temp = offset;
    assert(radeon_cntl_mem);
    if (index_mask) {
	temp = radeon_get(index_offset, "index");
	temp &= ~index_mask;
	temp += offset;
    }
    radeon_set(index_offset, "index", temp);
    return radeon_get(data_offset, name);
}

static void radeon_set_indexed(unsigned long index_offset,
                               unsigned long data_offset, unsigned long offset,
                               const char *name, unsigned int value, int index_mask)
{
    unsigned int temp = offset;
    assert(radeon_cntl_mem);
    if (index_mask) {
	temp = radeon_get(index_offset, "index");
	temp &= ~index_mask;
	temp += offset;
    }
    radeon_set(index_offset, "index", temp);
    radeon_set(data_offset, name, value);
}

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, 0x3f);
}

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, 0xff);
}

static unsigned int radeon_get_mcind(unsigned long offset, const char *name)
{
  return radeon_get_indexed(0x1f8, 0x1fc, offset, name, 0x3f);
}

static void radeon_set_mcind(unsigned long offset, const char *name,
			     unsigned int value)
{
  return radeon_set_indexed(0x1f8, 0x1fc, offset | (1 << 8), name, value, 0);
}

static void usage(void)
{
    const char *dac_status, *light_status;

    if (!radeon_cntl_mem) {
        dac_status = "";
        light_status = "";
    } else {
        dac_status = (radeon_get(RADEON_DAC_CNTL, "RADEON_DAC_CNTL") & RADEON_DAC_PDWN)
            ? " (off)" : " (on)";
        light_status = (radeon_get(RADEON_LVDS_GEN_CNTL,"RADEON_LVDS_GEN_CNTL") & RADEON_LVDS_ON)
            ? " (on)" : " (off)";
    }

    fprintf(stderr,"usage: radeontool [options] [command]\n");
    fprintf(stderr,"         --debug            - show a little debug info\n");
    fprintf(stderr,"         --skip=1           - use the second radeon card\n");
    fprintf(stderr,"         dac [on|off]       - power down the external video outputs%s\n",
	   dac_status);
    fprintf(stderr,"         light [on|off]     - power down the backlight%s\n",
	   light_status);
    fprintf(stderr,"         stretch [on|off|vert|horiz|auto|manual]   - stretching for resolution mismatch \n");
    fprintf(stderr,"         regs               - show a listing of some random registers\n");
    fprintf(stderr,"         regmatch <pattern> - show registers matching wildcard pattern\n");
    fprintf(stderr,"         regset <pattern> <value> - set registers matching wildcard pattern\n");
    exit(-1);
}

void radeon_cmd_regs(void)
{
#define SHOW_REG(r) printf("%s\t%08x\n", #r, radeon_get(r, #r))
#define SHOW_CLK_REG(r) printf("%s\t%08x\n", #r, radeon_get_indexed(RADEON_CLOCK_CNTL_INDEX, RADEON_CLOCK_CNTL_DATA, (r), #r, 0x3f))	
	if (!radeon_cntl_mem)
		exit(-1);
	SHOW_REG(RADEON_DAC_CNTL);
	SHOW_REG(RADEON_DAC_EXT_CNTL);
	SHOW_REG(RADEON_DAC_MACRO_CNTL);
	SHOW_REG(RADEON_DAC_CNTL2);
	SHOW_REG(RADEON_TV_DAC_CNTL);
	SHOW_REG(RADEON_DISP_OUTPUT_CNTL);
	SHOW_REG(RADEON_CONFIG_MEMSIZE);
	SHOW_REG(RADEON_AUX_SC_CNTL);
	SHOW_REG(RADEON_CRTC_EXT_CNTL);
	SHOW_REG(RADEON_CRTC_GEN_CNTL);
	SHOW_REG(RADEON_CRTC2_GEN_CNTL);
	SHOW_REG(RADEON_DEVICE_ID);
	SHOW_REG(RADEON_DISP_MISC_CNTL);
	SHOW_REG(RADEON_GPIO_MONID);
	SHOW_REG(RADEON_GPIO_MONIDB);
	SHOW_REG(RADEON_GPIO_CRT2_DDC);
	SHOW_REG(RADEON_GPIO_DVI_DDC);
	SHOW_REG(RADEON_GPIO_VGA_DDC);
	SHOW_REG(RADEON_LVDS_GEN_CNTL);
	SHOW_REG(RADEON_LVDS_PLL_CNTL);
	SHOW_REG(RADEON_FP_GEN_CNTL);
	SHOW_REG(RADEON_FP2_GEN_CNTL);
	SHOW_CLK_REG(RADEON_PPLL_CNTL);
	SHOW_CLK_REG(RADEON_PPLL_REF_DIV);
	SHOW_CLK_REG(RADEON_PPLL_DIV_3);
	SHOW_CLK_REG(RADEON_PIXCLKS_CNTL);
	SHOW_CLK_REG(RADEON_P2PLL_CNTL);
	SHOW_CLK_REG(RADEON_P2PLL_REF_DIV);
	SHOW_CLK_REG(RADEON_P2PLL_DIV_0);
	SHOW_CLK_REG(RADEON_VCLK_ECP_CNTL);
	SHOW_REG(RADEON_MEM_TIMING_CNTL);
	SHOW_REG(RADEON_TMDS_PLL_CNTL);
	SHOW_REG(RADEON_TMDS_TRANSMITTER_CNTL);
	SHOW_REG(RADEON_CRTC_MORE_CNTL);
	SHOW_REG(RADEON_FP_H_SYNC_STRT_WID);
	SHOW_REG(RADEON_FP_V_SYNC_STRT_WID);
	SHOW_REG(RADEON_FP_CRTC_H_TOTAL_DISP);
	SHOW_REG(RADEON_FP_CRTC_V_TOTAL_DISP);
	SHOW_REG(RADEON_FP_HORZ_STRETCH);
	SHOW_REG(RADEON_FP_VERT_STRETCH);
	SHOW_REG(RADEON_FP_HORZ_VERT_ACTIVE);
	SHOW_REG(RADEON_CRTC_H_TOTAL_DISP);
	SHOW_REG(RADEON_CRTC_H_SYNC_STRT_WID);
	SHOW_REG(RADEON_CRTC_V_TOTAL_DISP);
	SHOW_REG(RADEON_CRTC_V_SYNC_STRT_WID);
	SHOW_REG(RADEON_CRTC2_H_TOTAL_DISP);
	SHOW_REG(RADEON_CRTC2_H_SYNC_STRT_WID);
	SHOW_REG(RADEON_CRTC2_V_TOTAL_DISP);
	SHOW_REG(RADEON_CRTC2_V_SYNC_STRT_WID);
}

#define REGLIST(r) { "", #r, radeon_get, radeon_set, RADEON_ ## r }
#define REGLIST_CLK(r) { "CL: ", #r, radeon_get_clk, radeon_set_clk, RADEON_ ## r }
static struct {
    const char *type;
    const char *name;
    unsigned int (*get)(unsigned long, const char *);
    void (*set)(unsigned long, const char *, unsigned int);
    unsigned address;
} reg_list[] = {
	REGLIST(ADAPTER_ID),
	REGLIST(AGP_BASE),
	REGLIST(AGP_CNTL),
	REGLIST(AGP_COMMAND),
	REGLIST(AGP_STATUS),
	REGLIST(AMCGPIO_A_REG),
	REGLIST(AMCGPIO_EN_REG),
	REGLIST(AMCGPIO_MASK),
	REGLIST(AMCGPIO_Y_REG),
	REGLIST(ATTRDR),
	REGLIST(ATTRDW),
	REGLIST(ATTRX),
	REGLIST(AUX_SC_CNTL),
	REGLIST(AUX1_SC_BOTTOM),
	REGLIST(AUX1_SC_LEFT),
	REGLIST(AUX1_SC_RIGHT),
	REGLIST(AUX1_SC_TOP),
	REGLIST(AUX2_SC_BOTTOM),
	REGLIST(AUX2_SC_LEFT),
	REGLIST(AUX2_SC_RIGHT),
	REGLIST(AUX2_SC_TOP),
	REGLIST(AUX3_SC_BOTTOM),
	REGLIST(AUX3_SC_LEFT),
	REGLIST(AUX3_SC_RIGHT),
	REGLIST(AUX3_SC_TOP),
	REGLIST(AUX_WINDOW_HORZ_CNTL),
	REGLIST(AUX_WINDOW_VERT_CNTL),
	REGLIST(BASE_CODE),
	REGLIST(BIOS_0_SCRATCH),
	REGLIST(BIOS_1_SCRATCH),
	REGLIST(BIOS_2_SCRATCH),
	REGLIST(BIOS_3_SCRATCH),
	REGLIST(BIOS_4_SCRATCH),
	REGLIST(BIOS_5_SCRATCH),
	REGLIST(BIOS_6_SCRATCH),
	REGLIST(BIOS_7_SCRATCH),
	REGLIST(BIOS_ROM),
	REGLIST(BIST),
	REGLIST(BUS_CNTL),
	REGLIST(BUS_CNTL1),
	REGLIST(CACHE_CNTL),
	REGLIST(CACHE_LINE),
	REGLIST(CAP0_TRIG_CNTL),
	REGLIST(CAP1_TRIG_CNTL),
	REGLIST(CAPABILITIES_ID),
	REGLIST(CAPABILITIES_PTR),
	REGLIST(CLOCK_CNTL_DATA),
	REGLIST(CLOCK_CNTL_INDEX),
	REGLIST(CLR_CMP_CLR_3D),
	REGLIST(CLR_CMP_CLR_DST),
	REGLIST(CLR_CMP_CLR_SRC),
	REGLIST(CLR_CMP_CNTL),
	REGLIST(CLR_CMP_MASK),
	REGLIST(CLR_CMP_MASK_3D),
	REGLIST(COMMAND),
	REGLIST(COMPOSITE_SHADOW_ID),
	REGLIST(CONFIG_APER_0_BASE),
	REGLIST(CONFIG_APER_1_BASE),
	REGLIST(CONFIG_APER_SIZE),
	REGLIST(CONFIG_BONDS),
	REGLIST(CONFIG_CNTL),
	REGLIST(CONFIG_MEMSIZE),
	REGLIST(CONFIG_MEMSIZE_EMBEDDED),
	REGLIST(CONFIG_REG_1_BASE),
	REGLIST(CONFIG_REG_APER_SIZE),
	REGLIST(CONFIG_XSTRAP),
	REGLIST(CONSTANT_COLOR_C),
	REGLIST(CRC_CMDFIFO_ADDR),
	REGLIST(CRC_CMDFIFO_DOUT),
	REGLIST(CRTC_CRNT_FRAME),
	REGLIST(CRTC_DEBUG),
	REGLIST(CRTC_EXT_CNTL),
	REGLIST(CRTC_EXT_CNTL_DPMS_BYTE),
	REGLIST(CRTC_GEN_CNTL),
	REGLIST(CRTC2_GEN_CNTL),
	REGLIST(CRTC_GUI_TRIG_VLINE),
	REGLIST(CRTC_H_SYNC_STRT_WID),
	REGLIST(CRTC2_H_SYNC_STRT_WID),
	REGLIST(CRTC_H_TOTAL_DISP),
	REGLIST(CRTC2_H_TOTAL_DISP),
	REGLIST(CRTC_OFFSET),
	REGLIST(CRTC2_OFFSET),
	REGLIST(CRTC_OFFSET_CNTL),
	REGLIST(CRTC2_OFFSET_CNTL),
	REGLIST(CRTC_PITCH),
	REGLIST(CRTC2_PITCH),
	REGLIST(CRTC_STATUS),
	REGLIST(CRTC_V_SYNC_STRT_WID),
	REGLIST(CRTC2_V_SYNC_STRT_WID),
	REGLIST(CRTC_V_TOTAL_DISP),
	REGLIST(CRTC2_V_TOTAL_DISP),
	REGLIST(CRTC_VLINE_CRNT_VLINE),
	REGLIST(CRTC2_CRNT_FRAME),
	REGLIST(CRTC2_DEBUG),
	REGLIST(CRTC2_GUI_TRIG_VLINE),
	REGLIST(CRTC2_STATUS),
	REGLIST(CRTC2_VLINE_CRNT_VLINE),
	REGLIST(CRTC8_DATA),
	REGLIST(CRTC8_IDX),
	REGLIST(CUR_CLR0),
	REGLIST(CUR_CLR1),
	REGLIST(CUR_HORZ_VERT_OFF),
	REGLIST(CUR_HORZ_VERT_POSN),
	REGLIST(CUR_OFFSET),
	REGLIST(CUR2_CLR0),
	REGLIST(CUR2_CLR1),
	REGLIST(CUR2_HORZ_VERT_OFF),
	REGLIST(CUR2_HORZ_VERT_POSN),
	REGLIST(CUR2_OFFSET),
	REGLIST(DAC_CNTL),
	REGLIST(DAC_CNTL2),
	REGLIST(DAC_EXT_CNTL),
	REGLIST(DAC_MACRO_CNTL),
	REGLIST(TV_DAC_CNTL),
	REGLIST(DISP_OUTPUT_CNTL),
	REGLIST(DISPLAY_BASE_ADDR),
	REGLIST(DISPLAY2_BASE_ADDR),
	REGLIST(DAC_CRC_SIG),
	REGLIST(DAC_DATA),
	REGLIST(DAC_MASK),
	REGLIST(DAC_R_INDEX),
	REGLIST(DAC_W_INDEX),
	REGLIST(DDA_CONFIG),
	REGLIST(DDA_ON_OFF),
	REGLIST(DEFAULT_OFFSET),
	REGLIST(DEFAULT_PITCH),
	REGLIST(DEFAULT_SC_BOTTOM_RIGHT),
	REGLIST(DESTINATION_3D_CLR_CMP_VAL),
	REGLIST(DESTINATION_3D_CLR_CMP_MSK),
	REGLIST(DEVICE_ID),
	REGLIST(DISP_HW_DEBUG),
	REGLIST(DISP_MISC_CNTL),
	REGLIST(DP_BRUSH_BKGD_CLR),
	REGLIST(DP_BRUSH_FRGD_CLR),
	REGLIST(DP_CNTL),
	REGLIST(DP_CNTL_XDIR_YDIR_YMAJOR),
	REGLIST(DP_DATATYPE),
	REGLIST(DP_GUI_MASTER_CNTL),
	REGLIST(DP_GUI_MASTER_CNTL_C),
	REGLIST(DP_MIX),
	REGLIST(DP_SRC_BKGD_CLR),
	REGLIST(DP_SRC_FRGD_CLR),
	REGLIST(DP_WRITE_MASK),
	REGLIST(DST_BRES_DEC),
	REGLIST(DST_BRES_ERR),
	REGLIST(DST_BRES_INC),
	REGLIST(DST_BRES_LNTH),
	REGLIST(DST_BRES_LNTH_SUB),
	REGLIST(DST_HEIGHT),
	REGLIST(DST_HEIGHT_WIDTH),
	REGLIST(DST_HEIGHT_WIDTH_8),
	REGLIST(DST_HEIGHT_WIDTH_BW),
	REGLIST(DST_HEIGHT_Y),
	REGLIST(DST_LINE_START),
	REGLIST(DST_LINE_END),
	REGLIST(DST_LINE_PATCOUNT),
	REGLIST(DST_OFFSET),
	REGLIST(DST_PITCH),
	REGLIST(DST_PITCH_OFFSET),
	REGLIST(DST_PITCH_OFFSET_C),
	REGLIST(DST_WIDTH),
	REGLIST(DST_WIDTH_HEIGHT),
	REGLIST(DST_WIDTH_X),
	REGLIST(DST_WIDTH_X_INCY),
	REGLIST(DST_X),
	REGLIST(DST_X_SUB),
	REGLIST(DST_X_Y),
	REGLIST(DST_Y),
	REGLIST(DST_Y_SUB),
	REGLIST(DST_Y_X),
	REGLIST(FLUSH_1),
	REGLIST(FLUSH_2),
	REGLIST(FLUSH_3),
	REGLIST(FLUSH_4),
	REGLIST(FLUSH_5),
	REGLIST(FLUSH_6),
	REGLIST(FLUSH_7),
	REGLIST(FOG_3D_TABLE_START),
	REGLIST(FOG_3D_TABLE_END),
	REGLIST(FOG_3D_TABLE_DENSITY),
	REGLIST(FOG_TABLE_INDEX),
	REGLIST(FOG_TABLE_DATA),
	REGLIST(FP_CRTC_H_TOTAL_DISP),
	REGLIST(FP_CRTC_V_TOTAL_DISP),
	REGLIST(FP_CRTC2_H_TOTAL_DISP),
	REGLIST(FP_CRTC2_V_TOTAL_DISP),
	REGLIST(FP_GEN_CNTL),
	REGLIST(FP2_GEN_CNTL),
	REGLIST(FP_H_SYNC_STRT_WID),
	REGLIST(FP_H2_SYNC_STRT_WID),
	REGLIST(FP_HORZ_STRETCH),
	REGLIST(FP_HORZ2_STRETCH),
	REGLIST(FP_V_SYNC_STRT_WID),
	REGLIST(FP_VERT_STRETCH),
	REGLIST(FP_V2_SYNC_STRT_WID),
	REGLIST(FP_VERT2_STRETCH),
	REGLIST(FW_CNTL),
	REGLIST(FW_STATUS),
	REGLIST(GEN_INT_CNTL),
	REGLIST(GEN_INT_STATUS),
	REGLIST(GENENB),
	REGLIST(GENFC_RD),
	REGLIST(GENFC_WT),
	REGLIST(GENMO_RD),
	REGLIST(GENMO_WT),
	REGLIST(GENS0),
	REGLIST(GENS1),
	REGLIST(GPIO_MONID),
	REGLIST(GPIO_MONIDB),
	REGLIST(GPIO_CRT2_DDC),
	REGLIST(GPIO_DVI_DDC),
	REGLIST(GPIO_VGA_DDC),
	REGLIST(GRPH8_DATA),
	REGLIST(GRPH8_IDX),
	REGLIST(GRPH_BUFFER_CNTL),
	REGLIST(GRPH2_BUFFER_CNTL),
	REGLIST(MC_DEBUG),
	REGLIST(GUI_DEBUG0),
	REGLIST(GUI_DEBUG1),
	REGLIST(GUI_DEBUG2),
	REGLIST(GUI_DEBUG3),
	REGLIST(GUI_DEBUG4),
	REGLIST(GUI_DEBUG5),
	REGLIST(GUI_DEBUG6),
	REGLIST(GUI_SCRATCH_REG0),
	REGLIST(GUI_SCRATCH_REG1),
	REGLIST(GUI_SCRATCH_REG2),
	REGLIST(GUI_SCRATCH_REG3),
	REGLIST(GUI_SCRATCH_REG4),
	REGLIST(GUI_SCRATCH_REG5),
	REGLIST(HEADER),
	REGLIST(HOST_DATA0),
	REGLIST(HOST_DATA1),
	REGLIST(HOST_DATA2),
	REGLIST(HOST_DATA3),
	REGLIST(HOST_DATA4),
	REGLIST(HOST_DATA5),
	REGLIST(HOST_DATA6),
	REGLIST(HOST_DATA7),
	REGLIST(HOST_DATA_LAST),
	REGLIST(HOST_PATH_CNTL),
	REGLIST(HW_DEBUG),
	REGLIST(HW_DEBUG2),
	REGLIST(I2C_CNTL_1),
	REGLIST(DVI_I2C_CNTL_1),
	REGLIST(INTERRUPT_LINE),
	REGLIST(INTERRUPT_PIN),
	REGLIST(IO_BASE),
	REGLIST(LATENCY),
	REGLIST(LEAD_BRES_DEC),
	REGLIST(LEAD_BRES_LNTH),
	REGLIST(LEAD_BRES_LNTH_SUB),
	REGLIST(LVDS_GEN_CNTL),
	REGLIST(MAX_LATENCY),
	REGLIST(MC_AGP_LOCATION),
	REGLIST(MC_FB_LOCATION),
	REGLIST(MC_STATUS),
	REGLIST(MDGPIO_A_REG),
	REGLIST(MDGPIO_EN_REG),
	REGLIST(MDGPIO_MASK),
	REGLIST(MDGPIO_Y_REG),
	REGLIST(MEM_ADDR_CONFIG),
	REGLIST(MEM_BASE),
	REGLIST(MEM_CNTL),
	REGLIST(MEM_INIT_LAT_TIMER),
	REGLIST(MEM_INTF_CNTL),
	REGLIST(MEM_SDRAM_MODE_REG),
	REGLIST(MEM_STR_CNTL),
	REGLIST(MEM_TIMING_CNTL),
	REGLIST(MC_CNTL),
	REGLIST(MC_ARB_CNTL),
	REGLIST(MEM_VGA_RP_SEL),
	REGLIST(MEM_VGA_WP_SEL),
	REGLIST(MIN_GRANT),
	REGLIST(MM_DATA),
	REGLIST(MM_INDEX),
	REGLIST(MPP_TB_CONFIG),
	REGLIST(MPP_GP_CONFIG),
	REGLIST(N_VIF_COUNT),
	REGLIST(NB_TOM),
	REGLIST(OV0_SCALE_CNTL),
	REGLIST(OVR_CLR),
	REGLIST(OVR_WID_LEFT_RIGHT),
	REGLIST(OVR_WID_TOP_BOTTOM),
	REGLIST(OV0_Y_X_START),
	REGLIST(OV0_Y_X_END),
	REGLIST(OV0_EXCLUSIVE_HORZ),
	REGLIST(OV0_EXCLUSIVE_VERT),
	REGLIST(OV0_REG_LOAD_CNTL),
	REGLIST(OV0_SCALE_CNTL),
	REGLIST(OV0_V_INC),
	REGLIST(OV0_P1_V_ACCUM_INIT),
	REGLIST(OV0_P23_V_ACCUM_INIT),
	REGLIST(OV0_P1_BLANK_LINES_AT_TOP),
	REGLIST(OV0_P23_BLANK_LINES_AT_TOP),
	REGLIST(OV0_VID_BUF0_BASE_ADRS),
	REGLIST(OV0_VID_BUF1_BASE_ADRS),
	REGLIST(OV0_VID_BUF2_BASE_ADRS),
	REGLIST(OV0_VID_BUF3_BASE_ADRS),
	REGLIST(OV0_VID_BUF4_BASE_ADRS),
	REGLIST(OV0_VID_BUF5_BASE_ADRS),
	REGLIST(OV0_VID_BUF_PITCH0_VALUE),
	REGLIST(OV0_VID_BUF_PITCH1_VALUE),
	REGLIST(OV0_AUTO_FLIP_CNTL),
	REGLIST(OV0_DEINTERLACE_PATTERN),
	REGLIST(OV0_H_INC),
	REGLIST(OV0_STEP_BY),
	REGLIST(OV0_P1_H_ACCUM_INIT),
	REGLIST(OV0_P23_H_ACCUM_INIT),
	REGLIST(OV0_P1_X_START_END),
	REGLIST(OV0_P2_X_START_END),
	REGLIST(OV0_P3_X_START_END),
	REGLIST(OV0_FILTER_CNTL),
	REGLIST(OV0_FOUR_TAP_COEF_0),
	REGLIST(OV0_FOUR_TAP_COEF_1),
	REGLIST(OV0_FOUR_TAP_COEF_2),
	REGLIST(OV0_FOUR_TAP_COEF_3),
	REGLIST(OV0_FOUR_TAP_COEF_4),
	REGLIST(OV0_COLOUR_CNTL),
	REGLIST(OV0_VIDEO_KEY_CLR_LOW),
	REGLIST(OV0_VIDEO_KEY_CLR_HIGH),
	REGLIST(OV0_GRAPHICS_KEY_CLR_LOW),
	REGLIST(OV0_GRAPHICS_KEY_CLR_HIGH),
	REGLIST(OV0_KEY_CNTL),
	REGLIST(OV0_TEST),
	REGLIST(PALETTE_DATA),
	REGLIST(PALETTE_30_DATA),
	REGLIST(PALETTE_INDEX),
	REGLIST(PCI_GART_PAGE),
	REGLIST_CLK(PIXCLKS_CNTL),
	REGLIST_CLK(VCLK_ECP_CNTL),
	REGLIST_CLK(MPLL_CNTL),
	REGLIST_CLK(MCLK_CNTL),
	REGLIST_CLK(PPLL_DIV_0),
	REGLIST_CLK(PPLL_DIV_1),
	REGLIST_CLK(PPLL_DIV_2),
	REGLIST_CLK(PPLL_DIV_3),
	REGLIST_CLK(PPLL_REF_DIV),
	REGLIST_CLK(P2PLL_REF_DIV),
	REGLIST_CLK(P2PLL_DIV_0),
	REGLIST_CLK(PPLL_CNTL),
	REGLIST_CLK(P2PLL_CNTL),
	REGLIST_CLK(SPLL_CNTL),
	REGLIST_CLK(AGP_PLL_CNTL),
	REGLIST_CLK(HTOTAL_CNTL),
	REGLIST_CLK(HTOTAL2_CNTL),
	REGLIST_CLK(CLK_PIN_CNTL),
	REGLIST_CLK(CLK_PWRMGT_CNTL),
	REGLIST_CLK(PLL_PWRMGT_CNTL),
	REGLIST_CLK(SCLK_CNTL),
	REGLIST_CLK(CLK_TEST_ONE),
	REGLIST_CLK(PWRMAN_MISC),
	REGLIST_CLK(SS_INT_CNTL),
	REGLIST(PLANE_3D_MASK_C),
	REGLIST(PMI_CAP_ID),
	REGLIST(PMI_DATA),
	REGLIST(PMI_NXT_CAP_PTR),
	REGLIST(PMI_PMC_REG),
	REGLIST(PMI_PMCSR_REG),
	REGLIST(PMI_REGISTER),
	REGLIST(PWR_MNGMT_CNTL_STATUS),
	REGLIST(DSTCACHE_MODE),
	REGLIST(RBBM_SOFT_RESET),
	REGLIST(RBBM_STATUS),
	REGLIST(RB2D_DSTCACHE_CTLSTAT),
	REGLIST(RB2D_DSTCACHE_MODE),
	REGLIST(REG_BASE),
	REGLIST(REGPROG_INF),
	REGLIST(REVISION_ID),
	REGLIST(SC_BOTTOM),
	REGLIST(SC_BOTTOM_RIGHT),
	REGLIST(SC_BOTTOM_RIGHT_C),
	REGLIST(SC_LEFT),
	REGLIST(SC_RIGHT),
	REGLIST(SC_TOP),
	REGLIST(SC_TOP_LEFT),
	REGLIST(SC_TOP_LEFT_C),
	REGLIST(SDRAM_MODE_REG),
	REGLIST(SEQ8_DATA),
	REGLIST(SEQ8_IDX),
	REGLIST(SNAPSHOT_F_COUNT),
	REGLIST(SNAPSHOT_VH_COUNTS),
	REGLIST(SNAPSHOT_VIF_COUNT),
	REGLIST(SRC_OFFSET),
	REGLIST(SRC_PITCH),
	REGLIST(SRC_PITCH_OFFSET),
	REGLIST(SRC_SC_BOTTOM),
	REGLIST(SRC_SC_BOTTOM_RIGHT),
	REGLIST(SRC_SC_RIGHT),
	REGLIST(SRC_X),
	REGLIST(SRC_X_Y),
	REGLIST(SRC_Y),
	REGLIST(SRC_Y_X),
	REGLIST(STATUS),
	REGLIST(SUBPIC_CNTL),
	REGLIST(SUB_CLASS),
	REGLIST(SURFACE_CNTL),
	REGLIST(SURFACE0_INFO),
	REGLIST(SURFACE0_LOWER_BOUND),
	REGLIST(SURFACE0_UPPER_BOUND),
	REGLIST(SURFACE1_INFO),
	REGLIST(SURFACE1_LOWER_BOUND),
	REGLIST(SURFACE1_UPPER_BOUND),
	REGLIST(SURFACE2_INFO),
	REGLIST(SURFACE2_LOWER_BOUND),
	REGLIST(SURFACE2_UPPER_BOUND),
	REGLIST(SURFACE3_INFO),
	REGLIST(SURFACE3_LOWER_BOUND),
	REGLIST(SURFACE3_UPPER_BOUND),
	REGLIST(SURFACE4_INFO),
	REGLIST(SURFACE4_LOWER_BOUND),
	REGLIST(SURFACE4_UPPER_BOUND),
	REGLIST(SURFACE5_INFO),
	REGLIST(SURFACE5_LOWER_BOUND),
	REGLIST(SURFACE5_UPPER_BOUND),
	REGLIST(SURFACE6_INFO),
	REGLIST(SURFACE6_LOWER_BOUND),
	REGLIST(SURFACE6_UPPER_BOUND),
	REGLIST(SURFACE7_INFO),
	REGLIST(SURFACE7_LOWER_BOUND),
	REGLIST(SURFACE7_UPPER_BOUND),
	REGLIST(SW_SEMAPHORE),
	REGLIST(TEST_DEBUG_CNTL),
	REGLIST(TEST_DEBUG_MUX),
	REGLIST(TEST_DEBUG_OUT),
	REGLIST(TMDS_CRC),
	REGLIST(TRAIL_BRES_DEC),
	REGLIST(TRAIL_BRES_ERR),
	REGLIST(TRAIL_BRES_INC),
	REGLIST(TRAIL_X),
	REGLIST(TRAIL_X_SUB),
	REGLIST(PIXCLKS_CNTL),
	REGLIST(VENDOR_ID),
	REGLIST(VGA_DDA_CONFIG),
	REGLIST(VGA_DDA_ON_OFF),
	REGLIST(VID_BUFFER_CONTROL),
	REGLIST(VIDEOMUX_CNTL),
	REGLIST(VIPH_CONTROL),
	REGLIST(WAIT_UNTIL),
	REGLIST(RB3D_BLENDCNTL),
	REGLIST(RB3D_CNTL),
	REGLIST(RB3D_COLOROFFSET),
	REGLIST(RB3D_COLORPITCH),
	REGLIST(RB3D_DEPTHOFFSET),
	REGLIST(RB3D_DEPTHPITCH),
	REGLIST(RB3D_PLANEMASK),
	REGLIST(RB3D_ROPCNTL),
	REGLIST(RB3D_STENCILREFMASK),
	REGLIST(RB3D_ZSTENCILCNTL),
	REGLIST(RB3D_DSTCACHE_MODE),
	REGLIST(RE_LINE_PATTERN),
	REGLIST(RE_LINE_STATE),
	REGLIST(RE_MISC),
	REGLIST(RE_SOLID_COLOR),
	REGLIST(RE_TOP_LEFT),
	REGLIST(RE_WIDTH_HEIGHT),
	REGLIST(SE_CNTL_STATUS),
	REGLIST(LVDS_PLL_CNTL),
	REGLIST(TMDS_PLL_CNTL),
	REGLIST(TMDS_TRANSMITTER_CNTL),
	REGLIST(ISYNC_CNTL),
	REGLIST(TV_MASTER_CNTL),
	REGLIST(TV_PRE_DAC_MUX_CNTL),
	REGLIST(TV_RGB_CNTL),
	REGLIST(TV_SYNC_CNTL),
	REGLIST(TV_HTOTAL),
	REGLIST(TV_HDISP),
	REGLIST(TV_HSTART),
	REGLIST(TV_HCOUNT),
	REGLIST(TV_VTOTAL),
	REGLIST(TV_VDISP),
	REGLIST(TV_VCOUNT),
	REGLIST(TV_FTOTAL),
	REGLIST(TV_FCOUNT),
	REGLIST(TV_FRESTART),
	REGLIST(TV_HRESTART),
	REGLIST(TV_VRESTART),
	REGLIST(TV_VSCALER_CNTL1),
	REGLIST(TV_TIMING_CNTL),
	REGLIST(TV_VSCALER_CNTL2),
	REGLIST(TV_Y_FALL_CNTL),
	REGLIST(TV_Y_RISE_CNTL),
	REGLIST(TV_Y_SAW_TOOTH_CNTL),
	REGLIST(TV_UPSAMP_AND_GAIN_CNTL),
	REGLIST(TV_GAIN_LIMIT_SETTINGS),
	REGLIST(TV_LINEAR_GAIN_SETTINGS),
	REGLIST(TV_MODULATOR_CNTL1),
	REGLIST(TV_MODULATOR_CNTL2),
	REGLIST(TV_CRC_CNTL),
	REGLIST(TV_UV_ADR),
	REGLIST(GPIOPAD_A),
	REGLIST(RS480_UNK_e30),
	REGLIST(RS480_UNK_e34),
	REGLIST(RS480_UNK_e38),
	REGLIST(RS480_UNK_e3c),
};

void radeon_reg_match(const char *pattern)
{
    int i;
    unsigned long address;
    unsigned int value;

    if (!radeon_cntl_mem)
        exit(-1);
    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] == '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] == 'M' && pattern[1] == 'C' && pattern[2] == ':') {
        address = strtol(&(pattern[3]), NULL, 16);
        value = radeon_get_mcind(address, pattern);
        printf("%s\t0x%08x (%d)\n", pattern, value, value);
    }
    else {
        int crtc2_enabled;

        /* Prepare for a crash (just in case). */
        sync();

        /* dual-head setup? */
        value = radeon_get(RADEON_CRTC2_GEN_CNTL, "RADEON_CRTC2_GEN_CTRL");
        crtc2_enabled = (value & RADEON_CRTC2_EN) ? 1 : 0;

        for (i = 0; i < sizeof(reg_list) / sizeof(reg_list[0]); i++) {
            if (fnmatch(pattern, reg_list[i].name, 0) == 0) {
                if (!crtc2_enabled &&
                    (reg_list[i].address == RADEON_CRTC2_CRNT_FRAME ||
                     reg_list[i].address == RADEON_CRTC2_VLINE_CRNT_VLINE))
                    /* might freeze, so skip it */
                    continue;

                printf("%s (%s%04x)\t", reg_list[i].name,
                       reg_list[i].type, reg_list[i].address);

                /* Force output in case the register read locks up. */
                fflush(stdout);
                fsync(STDOUT_FILENO);

                value = reg_list[i].get(reg_list[i].address, reg_list[i].name);
                printf("0x%08x (%d)\n", value, value);
            }
        }
	if (pattern[0] == '*') {
 	     for (i = 0; i < 0x2f; i++) {
	         value = radeon_get_mcind(i, "MC");
	         printf("MC: 0x%02x\t0x%08x\n", i, 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 (!radeon_cntl_mem)
        exit(-1);
    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] == '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 {
        for (i = 0; i < sizeof(reg_list) / sizeof(reg_list[0]); i++) {
            if (fnmatch(inname, reg_list[i].name, 0) == 0) {
                set_reg(reg_list[i].name, reg_list[i].type, reg_list[i].address,
                        value, reg_list[i].get, reg_list[i].set);
            }
        }
    }
}

void radeon_cmd_bits(void)
{
    unsigned int dac_cntl;

    if (!radeon_cntl_mem)
        exit(-1);
    dac_cntl = radeon_get(RADEON_DAC_CNTL,"RADEON_DAC_CNTL");  
    printf("RADEON_DAC_CNTL=%08x (",dac_cntl);  
    if(dac_cntl & RADEON_DAC_RANGE_CNTL)
        printf("range_cntl ");  
    if(dac_cntl & RADEON_DAC_BLANKING)
        printf("blanking ");  
    if(dac_cntl & RADEON_DAC_8BIT_EN)
        printf("8bit_en ");  
    if(dac_cntl & RADEON_DAC_VGA_ADR_EN)
        printf("vga_adr_en ");  
    if(dac_cntl & RADEON_DAC_PDWN)
        printf("pdwn ");  
    printf(")\n");  
}

void radeon_cmd_dac(char *param)
{
    unsigned long dac_cntl;

    if (!radeon_cntl_mem)
        exit(-1);
    dac_cntl = radeon_get(RADEON_DAC_CNTL,"RADEON_DAC_CNTL");
    if(param == NULL) {
        printf("The radeon external DAC looks %s\n",(dac_cntl&(RADEON_DAC_PDWN))?"off":"on");
        exit (-1);
    } else if(strcmp(param,"off") == 0) {
        dac_cntl |= RADEON_DAC_PDWN;
    } else if(strcmp(param,"on") == 0) {
        dac_cntl &= ~ RADEON_DAC_PDWN;
    } else {
        usage();	    
    };
    radeon_set(RADEON_DAC_CNTL,"RADEON_DAC_CNTL",dac_cntl);
}

void radeon_cmd_light(char *param)
{
    unsigned long lvds_gen_cntl;

    if (!radeon_cntl_mem)
        exit(-1);
    lvds_gen_cntl = radeon_get(RADEON_LVDS_GEN_CNTL,"RADEON_LVDS_GEN_CNTL");
    if(param == NULL) {
        printf("The radeon backlight looks %s\n",(lvds_gen_cntl&(RADEON_LVDS_ON))?"on":"off");
        exit (-1);
    } else if(strcmp(param,"on") == 0) {
        lvds_gen_cntl |= RADEON_LVDS_ON;
    } else if(strcmp(param,"off") == 0) {
        lvds_gen_cntl &= ~ RADEON_LVDS_ON;
    } else {
        usage();	    
    };
    radeon_set(RADEON_LVDS_GEN_CNTL,"RADEON_LVDS_GEN_CNTL",lvds_gen_cntl);
}

void radeon_cmd_stretch(char *param)
{
    unsigned long fp_vert_stretch,fp_horz_stretch;

    if (!radeon_cntl_mem)
        exit(-1);
    fp_vert_stretch = radeon_get(RADEON_FP_VERT_STRETCH,"RADEON_FP_VERT_STRETCH");
    fp_horz_stretch = radeon_get(RADEON_FP_HORZ_STRETCH,"RADEON_FP_HORZ_STRETCH");
    if(param == NULL) {
        printf("The horizontal stretching looks %s\n",(fp_horz_stretch&(RADEON_HORZ_STRETCH_ENABLE))?"on":"off");
        printf("The vertical stretching looks %s\n",(fp_vert_stretch&(RADEON_VERT_STRETCH_ENABLE))?"on":"off");
        exit (-1);
    } else if(strncmp(param,"ver",3) == 0) {
        fp_horz_stretch &= ~ RADEON_HORZ_STRETCH_ENABLE;
        fp_vert_stretch |= RADEON_VERT_STRETCH_ENABLE;
    } else if(strncmp(param,"hor",3) == 0) {
        fp_horz_stretch |= RADEON_HORZ_STRETCH_ENABLE;
        fp_vert_stretch &= ~ RADEON_VERT_STRETCH_ENABLE;
    } else if(strcmp(param,"on") == 0) {
        fp_horz_stretch |= RADEON_HORZ_STRETCH_ENABLE;
        fp_vert_stretch |= RADEON_VERT_STRETCH_ENABLE;
    } else if(strcmp(param,"auto") == 0) {
        fp_horz_stretch |= RADEON_HORZ_AUTO_RATIO;
        fp_horz_stretch |= RADEON_HORZ_AUTO_RATIO_INC;
        fp_horz_stretch |= RADEON_HORZ_STRETCH_ENABLE;
        fp_vert_stretch |= RADEON_VERT_AUTO_RATIO_EN;
        fp_vert_stretch |= RADEON_VERT_STRETCH_ENABLE;
    } else if(strcmp(param,"manual") == 0) {
        fp_horz_stretch &= ~ RADEON_HORZ_AUTO_RATIO;
        fp_horz_stretch &= ~ RADEON_HORZ_AUTO_RATIO_INC;
        fp_horz_stretch |= RADEON_HORZ_STRETCH_ENABLE;
        fp_vert_stretch &= ~ RADEON_VERT_AUTO_RATIO_EN;
        fp_vert_stretch |= RADEON_VERT_STRETCH_ENABLE;
    } else if(strcmp(param,"off") == 0) {
        fp_horz_stretch &= ~ RADEON_HORZ_STRETCH_ENABLE;
        fp_vert_stretch &= ~ RADEON_VERT_STRETCH_ENABLE;
    } else {
        usage();	    
    };
    radeon_set(RADEON_FP_HORZ_STRETCH,"RADEON_FP_HORZ_STRETCH",fp_horz_stretch);
    radeon_set(RADEON_FP_VERT_STRETCH,"RADEON_FP_VERT_STRETCH",fp_vert_stretch);
}


/* Look for the Radeon hardware address. */
static void map_radeon_cntl_mem(void)
{
    struct pci_slot_match match;
    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) {
        fprintf(stderr, "error: failed to initialise libpciaccess: %s\n",
		strerror(ret));
        return;
    }

    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);

    while ((device = pci_device_next(iter))) {
        pci_device_probe(device);
        if (device->vendor_id != 0x1002)
            continue;
        if ((device->device_class & 0x00ffff00) != 0x00030000)
            continue;

        if (debug)
            printf("Found card %x:%x (%x)\n", device->vendor_id,
                   device->device_id, device->device_class);
        if (skip--)
            continue;
        break;
    }

    if (!device) {
        fprintf(stderr, "error: cannot find Radeon device\n");
        return;
    }

    ctrl_base = device->regions[2].base_addr;
    ctrl_size = device->regions[2].size;
    if (!ctrl_size) {
        fprintf(stderr, "error: missing ctrl region\n");
        return;
    }
    ret = pci_device_map_range(device, ctrl_base, ctrl_size,
			     PCI_DEV_MAP_FLAG_WRITABLE, (void **) &ctrl_mem);
    if (ret) {
        fprintf(stderr, "cannot map ctrl region: %s\n", strerror(ret));
        return;
    }

    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);

    if (debug)
        printf("Radeon found. Base control address is %lx; "
               "base framebuffer address is %lx.\n",
               (unsigned long) ctrl_mem, (unsigned long) fb_mem);

    if (!ctrl_mem)
        die("internal error");
    radeon_cntl_mem = ctrl_mem;
}

#ifdef __powerpc__
#define __swab16(x) \
({ \
        unsigned short __x = (x); \
        ((unsigned short)( \
                (((unsigned short)(__x) & (unsigned short)0x00ffU) << 8) | \
                (((unsigned short)(__x) & (unsigned short)0xff00U) >> 8) )); \
})
#define __swab32(x) \
({ \
	unsigned int __x = (x); \
	((unsigned int)( \
		(((unsigned int)(__x) & (unsigned int)0x000000ffUL) << 24) | \
		(((unsigned int)(__x) & (unsigned int)0x0000ff00UL) <<  8) | \
		(((unsigned int)(__x) & (unsigned int)0x00ff0000UL) >>  8) | \
		(((unsigned int)(__x) & (unsigned int)0xff000000UL) >> 24) )); \
})
#define BIOS16(offset)	__swab16(*((unsigned short *)(bios + (offset))))
#define BIOS32(offset)	__swab32(*((unsigned int *)(bios + (offset))))
#else
#define BIOS16(offset)	(*((unsigned short *)(bios + (offset))))
#define BIOS32(offset)	(*((unsigned int *)(bios + (offset))))
#endif
#define BIOS8(offset)   (*((unsigned char *)(bios + (offset))))

struct nametable_entry
{
	unsigned int value;
	const char *name;
};

const char *radeon_valname(const struct nametable_entry *table, unsigned int value)
{
	static char ret_buf[256];
	while(table->name) {
		if (table->value == value)
			return table->name;
		table++;
	}
	sprintf(ret_buf, "<unknown val %d>", value);
	return ret_buf;
}

static struct nametable_entry hdr_type_name[] = {
	{ 2, "Rage128 & Pro"},
	{ 3, "Rage M3"},
	{ 4, "Radeon"},
	{ 36, "ATOM" },
	{ 0, NULL}
};

static void radeon_rom_legacy_clocks(unsigned char *bios, int hdr)
{
	int pll_info_block = BIOS16(hdr + 0x30);
	int rev;

	if (pll_info_block == 0) {
		printf("No clock info block in BIOS\n");
		return;
	}
	rev = BIOS8(pll_info_block);
	printf("revision %d\n", rev);

	printf("Clock info block:\n");
	printf("  SCLK   : %f\n", BIOS16(pll_info_block + 0x0a) / 100.0);
	printf("  MCLK   : %f\n", BIOS16(pll_info_block + 0x08) / 100.0);
	printf("  RefClk : %f\n", BIOS16(pll_info_block + 0x0e) / 100.0);
	printf("  RefDiv : %d\n", BIOS16(pll_info_block + 0x10));
	printf("  VCO Min: %f\n", BIOS32(pll_info_block + 0x12) / 100.0);
	printf("  VCO Max: %f\n", BIOS32(pll_info_block + 0x16) / 100.0);

	if (rev > 9) {
	    printf("  VCO in Min: %f\n", BIOS32(pll_info_block + 0x36) / 100.0);
	    printf("  VCO in Max: %f\n", BIOS32(pll_info_block + 0x3a) / 100.0);
	    printf("  VCO out Min: %f\n", BIOS32(pll_info_block + 0x3e) / 100.0);
	    printf("  VCO out Max: %f\n", BIOS32(pll_info_block + 0x42) / 100.0);
	}

	printf("  SPLL RefClk  : %f\n", BIOS16(pll_info_block + 0x1a) / 100.0);
	printf("  SPLL ref div  : %d\n", BIOS16(pll_info_block + 0x1c));
	printf("  VCO Min: %f\n", BIOS32(pll_info_block + 0x1e) / 100.0);
	printf("  VCO Max: %f\n", BIOS32(pll_info_block + 0x22) / 100.0);

	printf("  MPLL RefClk  : %f\n", BIOS16(pll_info_block + 0x26) / 100.0);
	printf("  MPLL ref div  : %d\n", BIOS16(pll_info_block + 0x28));
	printf("  VCO Min: %f\n", BIOS32(pll_info_block + 0x2a) / 100.0);
	printf("  VCO Max: %f\n", BIOS32(pll_info_block + 0x2e) / 100.0);

	printf("\n");
}

static void radeon_rom_atom_clocks(unsigned char *bios, int master)
{

	int pll_info_block = BIOS16(master + 12);

	if (pll_info_block == 0) {
	  printf("No clock info block in BIOS\n");
	}

	printf("Clock info block:\n");
	printf("  SCLK    : %f\n", BIOS32(pll_info_block + 8) / 100.0);
	printf("  MCLK    : %f\n", BIOS32(pll_info_block + 12) / 100.0);
	printf("  RefClk  : %f\n", BIOS16(pll_info_block + 82) / 100.0);
	printf("  PPLL in Min: %f\n", BIOS16(pll_info_block + 74) / 100.0);
	printf("  PPLL in Max: %f\n", BIOS16(pll_info_block + 76) / 100.0);
	printf("  PPLL out Min: %f\n", BIOS16(pll_info_block + 78) / 100.0);
	printf("  PPLL out Max: %f\n", BIOS32(pll_info_block + 32) / 100.0);
}


static struct nametable_entry lconn_type_name[] = {
	{ 0, "None"},
	{ 1, "Proprietary"},
	{ 2, "VGA"},
	{ 3, "DVI-I"},
	{ 4, "DVI-D"},
	{ 5, "CTV"},
	{ 6, "STV"},
	{ 7, "Unsupported"},
	{ 0, NULL}
};

static struct nametable_entry lddc_type_name[] = {
	{ 0, "None"},
	{ 1, "MONID"},
	{ 2, "DVI"},
	{ 3, "VGA"},
	{ 4, "CRT2"},
	{ 0, NULL}
};

static struct nametable_entry ldac_type_name[] = {
	{ 0, "CRT"},
	{ 1, "TV"},
	{ 2, "External"},
	{ 0, NULL}
};

static void radeon_rom_legacy_connectors(unsigned char *bios, int hdr)
{
	int offset = BIOS16(hdr + 0x50);
	int i, entry, tmp, chips, entries;

	if (offset == 0) {
		printf("No connector table in BIOS\n");
		return;
	}

	printf("Connector table:\n");

#if 0
	printf("  raw: %02x %02x %02x %02x %02x %02x %02x %02x\n",
	       BIOS8(offset+0), BIOS8(offset+1), BIOS8(offset+2),
	       BIOS8(offset+3), BIOS8(offset+4), BIOS8(offset+5),
	       BIOS8(offset+6), BIOS8(offset+7));
#endif


	chips = BIOS8(offset) >> 4; 
	printf("  Table revision %d for %d chip(s)\n",
	       BIOS8(offset) & 0xf, chips);
	if (chips > 1)
		printf("  Only 1 chip supported for now !\n");
	entries = BIOS8(offset + 1) & 0xf;
	printf("  Table for chip %d has %d connector(s):\n",
	       BIOS8(offset + 1) >> 4, entries);
	for (i = 0; i < entries; i++) {
		entry = offset + 2 + i*2;

		/* End of table */
		if (!BIOS16(entry)) {
			if (i < entries)
				printf("    <table early termination !>\n");
			break;
		}

		/* Read table entry, check connector type */
		tmp = BIOS16(entry);
		printf("    %08x  ", tmp);
		printf("Type:%s", radeon_valname(lconn_type_name,
						 (tmp >> 12) & 0xf));
		if (((tmp >> 8) & 0xf) == 5) {
		    printf(", DDC:0x%x", BIOS8(entry+2));
		} else {
		    printf(", DDC:%s", radeon_valname(lddc_type_name,
						      (tmp >> 8) & 0xf));
		}
		printf(", DAC:%s", radeon_valname(ldac_type_name, tmp & 0x3));
		printf(", TMDS:%s", (tmp & 0x10) ? "External" : "Internal");
		printf(", MUX switch:%s", (tmp & 0x20) ? "yes" : "no");



		printf("\n");
	}
	printf("\n");
}

static struct nametable_entry atomconn_type_name[] = {
	{ 0, "None"},
	{ 1, "VGA"},
	{ 2, "DVI-I"},
	{ 3, "DVI-D"},
	{ 4, "DVI-A"},
	{ 5, "STV"},
	{ 6, "CTV"},
	{ 7, "LVDS"},
	{ 8, "Digital"},
	{ 9, "SCART"},
	{ 10, "HDMI A"},
	{ 11, "HDMI B"},
	{ 14, "Special DIN"},
	{ 15, "Unsupported"},
	{ 0, NULL}
};

static void radeon_rom_atom_connectors(unsigned char *bios, int master)
{
	int offset = BIOS16(master + 22);
	int tmp, i, tmp0;
	int crtc, dac, connector, ddc=0;

	if (offset == 0) {
		printf("No connector table in BIOS\n");
		return;
	}

	tmp = BIOS16(offset + 4);
	printf("Connector table:\n");
	for (i=0; i<16; i++) {
		if (tmp & (1<<i)) {
		    switch (i) {
		    case 0:
			printf("CRT1 ");
			break;
		    case 1:
			printf("LCD1 ");
			break;
		    case 2:
			printf("TV1 ");
			break;
		    case 3:
			printf("DFP1 ");
			break;
		    case 4:
			printf("CRT2 ");
			break;
		    case 5:
			printf("LCD2 ");
			break;
		    case 6:
			printf("TV2 ");
			break;
		    case 7:
			printf("DFP2 ");
			break;
		    case 8:
			printf("CV ");
			break;
		    case 9:
			printf("DFP3 ");
			break;
		    default:
			printf("unknown ");
		    }

			int portinfo = BIOS16(offset+6+i*2);

			crtc = (portinfo >> 8) & 0xf;
			dac = (portinfo & 0xf) - 1;
			connector = (portinfo >> 4) & 0xf;

			printf("output id: %d\n", crtc);

			tmp0 = BIOS16(master + 24);
			if (1/*crtc*/) {
				int gpio = BIOS16(tmp0 + 4 + 27 * crtc) * 4;
				printf("gpio is %02X\n", gpio);
				switch(gpio)
				{
				case RADEON_GPIO_MONID: ddc = 1; break;
				case RADEON_GPIO_DVI_DDC: ddc = 2; break;
				case RADEON_GPIO_VGA_DDC: ddc = 3; break;
				case RADEON_GPIO_CRT2_DDC: ddc = 4; break;
				default: ddc=0; break;
				}
			}

			printf("%d:    %08x ", i, portinfo);
			printf(", Id:%d", crtc);
			printf(", Type:%s",  radeon_valname(atomconn_type_name, connector));
			if (1/*crtc*/)
				printf(", DDC:%s", radeon_valname(lddc_type_name,
								  ddc));
			printf(", DAC:%s",  radeon_valname(ldac_type_name, dac));
			if (i==3)
				printf(" TMDS: Internal\n");
			else if (i==7)
				printf(" TMDS: External\n");
			else if (i==9)
				printf(" TMDS: LVTMA\n");
			else
				printf("\n");
				
		}
	}
}

static void radeon_rom_legacy_lcdtable(unsigned char *bios, int hdr)
{
	int offset, i, type_info, extended_offset;
	unsigned int setup;
	char stmp[30];

	offset = BIOS16(hdr + 0x40);
	if (offset == 0) {
		printf("No LCD info table\n");
		return;
	}
	printf("\nLCD info table:\n");
	printf("lcd panel id: %d\n", BIOS8(offset));
	for (i = 0; i < 24; i++)
	    stmp[i] = BIOS8(offset+i+1);
	stmp[24] = 0;
	printf("lcd panel id string: %s\n", stmp);
	printf("lcd panel x: %d\n", BIOS16(offset+0x19));
	printf("lcd panel y: %d\n", BIOS16(offset+0x1b));

	type_info = BIOS16(offset+0x1d);
	if (type_info & 0x1)
	    printf("color ");
	else
	    printf("mono ");

	if (type_info & 0x2)
	    printf("single ");
	else
	    printf("dual ");

	switch ((type_info & 0xfc) >> 2) {
	case 0:
	    printf("STN\n");
	    break;
	case 1:
	default:
	    printf("TFT\n");
	    break;
	case 2:
	    printf("active addressed STN\n");
	    break;
	case 3:
	    printf("EL\n");
	    break;
	case 4:
	    printf("Plasma\n");
	    break;
	}

	printf("lcd panel power delay: %d\n", BIOS16(offset+0x24));

	extended_offset = BIOS16(offset+0x26);
	if (extended_offset) {
	  int extended_rev;
		extended_rev = BIOS8(extended_offset);
		printf("lcd panel extended info offset: %x\n", extended_offset);
		printf("lcd extended info rev: %x\n", extended_rev);
		
		printf("SS delay %x step size %x\n", BIOS8(extended_offset+1),
		       BIOS8(extended_offset + 2));

		if (extended_rev > 1) {
			printf("lcd fake edid id num  bytes %d\n", BIOS8(extended_offset+3));
			printf("lcd fake edid id num offset 0x%x\n", BIOS16(extended_offset+4));
		}
		if (extended_rev > 2) {
			printf("lcd LVPVS %x\n", BIOS8(extended_offset+6));
			printf("lcd PVG/PCP %x\n", BIOS8(extended_offset+7));
			printf("lcd SSPLL table offset %x\n", BIOS16(extended_offset+8));
		}
		if (extended_rev > 3) {
			printf("lcd resp time coeff 0x%x\n", BIOS8(extended_offset+10));
		}
		if (extended_rev > 4) {
			printf("edid low refresh offset 0x%x\n", BIOS16(extended_offset+11));
		}
	}

	printf("lcd panel vcc delay: %d\n", BIOS16(offset+0x2c));
	printf("lcd panel ref div: %d\n", BIOS16(offset+0x2e));
	printf("lcd panel post div: %d\n", BIOS8(offset+0x30));
	printf("lcd panel fb div: %d\n", BIOS16(offset+0x31));
	printf("SS type: %s / %s\n", (BIOS8(offset + 0x33) & 1) ? "center" : "down",
	       (BIOS8(offset + 0x33) & (1<<7)) ? "internal" : "external");
	printf("SS percentage %x\n", BIOS16(offset + 0x34));
	printf("lcd panel DIGON to LVDS active: %d\n", BIOS8(offset+0x38) & 0xf);
	printf("lcd panel LVDS active to BLON: %d\n", (BIOS8(offset+0x38) >> 4) & 0xf);
	setup = BIOS32(offset+0x39);
	printf("lcd panel LVDS setup: 0x%x\n", setup);

	if (setup & 0x1)
	    printf("888 RGB\n");
	else
	    printf("666 RGB\n");

	switch ((setup >> 8) & 0x8) {
	case 0:
	    printf("no frame modulation\n");
	    break;
	case 1:
	    printf("2 levels of grey\n");
	    break;
	case 2:
	    printf("4 levels of grey\n");
	    break;
	default:
	    printf("STN panel\n");
	    break;
	}

	if ((setup >> 16) & 0x1)
	    printf("frame pulse high\n");
	else
	    printf("frame pulse low\n");

	if ((setup >> 17) & 0x1)
	    printf("line pulse high\n");
	else
	    printf("line pulse low\n");

	if ((setup >> 18) & 0x1)
	    printf("MOD high\n");
	else
	    printf("MOD low\n");

	if ((setup >> 23) & 0x1)
	    printf("backlight mod 29 Mhz\n");
	else
	    printf("backlight mod 29 Mhz / 3\n");
}

static void radeon_rom_legacy_mobiletable(unsigned char *bios, int hdr)
{
	int offset, rev, i, gpiooffset, blocks, powerplayoffset, lcdddcoffset, tmdspoweroffset;
	unsigned int reg, andmask, ormask;

	offset = BIOS16(hdr + 0x42);
	if (offset == 0) {
		printf("No mobile info table\n");
		return;
	}
	rev = BIOS8(offset);
	printf("mobile table revision: %d\n", rev);

	switch (BIOS8(offset + 0x8) & 0xf) {
	case 1:
	    printf("CRT i2c clk=GPIO0, data=GPIO1\n");
	    break;
	case 2:
	    printf("CRT i2c clk=GPIO4, data=GPIO3\n");
	    break;
	default:
	    printf("%d\n", BIOS8(offset + 0x8) & 0xf);
	    break;
	}

	gpiooffset = BIOS16(offset+0x13);
	if (gpiooffset) {
	    printf("gpio table revision: %d\n", BIOS8(gpiooffset));
	    blocks = BIOS8(gpiooffset + 0x2);
	    printf("gpio blocks: %d\n", blocks);

	    for (i = 0; i < blocks; i++) {
		reg = BIOS16(gpiooffset + 3 + (i * 10) + 0);
		andmask = BIOS32(gpiooffset + 3 + (i * 10) + 0x2);
		ormask = BIOS32(gpiooffset + 3 + (i * 10) + 0x6);
		printf("reg: 0x%x, AND: 0x%x, OR: 0x%x\n", reg * 4, andmask, ormask);
	    }
	}
	powerplayoffset = BIOS16(offset+0x11);
	if (powerplayoffset) {
	    unsigned int powerplay_flags;
	    int powerplay_rev = BIOS8(powerplayoffset);
	    printf("powerplay table revision: %d\n", powerplay_rev);
	    printf("powerplay table size: %d bytes\n", BIOS8(powerplayoffset) + 1);
	    blocks = BIOS8(powerplayoffset+0x2);
	    printf("powerplay states: %d\n", blocks);
	    for (i = 0; i < blocks; i++) {
		printf("state %d\n", i);
		powerplay_flags = BIOS16(powerplayoffset + 5 + (i * 0x10));
		if (powerplay_flags & 0x1)
		    printf("\tMCLK_SRC_SPLL\n");
		else if (powerplay_flags & 0x2)
		    printf("\tSCLK_SRC_MPLL\n");
		else
		    printf("\tsplit clock\n");
		if (powerplay_flags & 0x4) {
		    printf("\tvoltage drop supported\n");
		    if (powerplay_flags & 0x8)
			printf("\tvoltage drop active high\n");
		    else
			printf("\tvoltage drop active low\n");
		}
		if (powerplay_flags & 0x10)
		    printf("\tlcd refresh rate change\n");
		if (powerplay_flags & 0x20)
		    printf("\tengine clk control enabled\n");
		if (powerplay_flags & 0x40)
		    printf("\tmemory clk control enabled\n");
		if (powerplay_flags & 0x80)
		    printf("\toverclock mode\n");
		else if (powerplay_rev <= 3)
		    printf("\tpowersave mode\n");
		if (powerplay_flags & 0x100)
		    printf("\thalf engine clk\n");
		if (powerplay_flags & 0x200)
		    printf("\tdynamic voltage control enabled\n");
		if (powerplay_flags & 0x400)
		    printf("\tpower state sleep mode enabled\n");
		if (powerplay_flags & 0x800)
		    printf("\tpower state load balancing enabled\n");
		if (powerplay_flags & 0x1000)
		    printf("\tdefault DC state\n");
		if (powerplay_flags & 0x2000)
		    printf("\tdefault DC low state\n");
		if (powerplay_rev > 3) {
		    if (powerplay_flags & 0x4000)
			printf("\tpowersave mode\n");
		    if (powerplay_flags & 0x8000)
			printf("\tthermal diode mode\n");
		}
		printf("\tmclk/sclk: %f/%f\n",
		       BIOS32(powerplayoffset + 5 + (i * 0x10) + 0x2) / 100.0,
		       BIOS32(powerplayoffset + 5 + (i * 0x10) + 0x6) / 100.0);
		switch (BIOS8(powerplayoffset + 5 + (i * 0x10) + 0xa)) {
		case 0:
		    printf("\tLCD refresh: 50 Hz\n");
		    break;
		case 2:
		    printf("\tLCD refresh: 56 Hz\n");
		    break;
		case 4:
		    printf("\tLCD refresh: 60 Hz\n");
		    break;
		case 6:
		    printf("\tLCD refresh: 67 Hz\n");
		    break;
		case 8:
		    printf("\tLCD refresh: 70 Hz\n");
		    break;
		case 10:
		    printf("\tLCD refresh: 72 Hz\n");
		    break;
		case 12:
		    printf("\tLCD refresh: 75 Hz\n");
		    break;
		case 14:
		    printf("\tLCD refresh: 76 Hz\n");
		    break;
		case 16:
		    printf("\tLCD refresh: 85 Hz\n");
			break;
		case 18:
		    printf("\tLCD refresh: 90 Hz\n");
		    break;
		case 20:
		    printf("\tLCD refresh: 100 Hz\n");
		    break;
		case 22:
		    printf("\tLCD refresh: 120 Hz\n");
		    break;
		case 24:
		    printf("\tLCD refresh: 140 Hz\n");
		    break;
		case 26:
		    printf("\tLCD refresh: 150 Hz\n");
		    break;
		case 28:
		    printf("\tLCD refresh: 160 Hz\n");
		    break;
		case 30:
		    printf("\tLCD refresh: 200 Hz\n");
		    break;
		case 1:
		    printf("\tLCD refresh: 40 Hz\n");
		    break;
		case 3:
		    printf("\tLCD refresh: 30 Hz\n");
		    break;
		default:
		    break;
		}
		if (powerplay_rev < 6) {
		    printf("\tvoltage control reg: 0x%x\n", BIOS16(powerplayoffset + 5 + (i * 0x10) + 0xb) * 4);
		    printf("\tvoltage control bits: %d\n", BIOS8(powerplayoffset + 5 + (i * 0x10) + 0xd));
		} else {
		    int j;
		    int entries = BIOS8(powerplayoffset + 5 + (i * 0x10) + 0xb);
		    int voltage_table_offset = BIOS16(powerplayoffset + 5 + (i * 0x10) + 0xc);
		    if (entries && voltage_table_offset) {
			printf("\t%d entries in voltage drop table\n", entries);
			printf("\tvoltage drop table at 0x%x\n", voltage_table_offset);
			for (j = 0; j < entries; j++) {
			    printf("\t\tvoltage drop register: 0x%x\n",
				   BIOS16(voltage_table_offset) * 4);
			    printf("\t\tvoltage drop register bits: %d\n",
				   BIOS8(voltage_table_offset + 0x2));
			}
		    }
		}
		if (powerplay_rev < 5) {
		    if (BIOS16(powerplayoffset + 5 + (i * 0x10) + 0xe))
			printf("\tpowerplay memory reset table at 0x%x\n",
			       BIOS16(powerplayoffset + 5 + (i * 0x10) + 0xe));
		} else {
		    int powerplay_flags2 = BIOS16(powerplayoffset + 5 + (i * 0x10) + 0xe);
		    if (powerplay_flags2 & 0x1)
			printf("\tenable frame modulation w/ 2 level grey\n");
		    else if (powerplay_flags2 & 0x2)
			printf("\tenable frame modulation w/ 4 level grey\n");
		    else
			printf("\tdisable frame modulation\n");
		    if (powerplay_flags2 & 0x4)
			printf("\tenable dynamic half clock\n");
		    if (powerplay_flags2 & 0x8)
			printf("\tenable dynamic clock on static screen\n");
		    if (powerplay_flags2 & 0x10)
			printf("\tenable dynamic clocking in 2D\n");
		    if ((powerplay_flags2 & 0xe0) == 0x20)
			printf("\tdynamic clocking divider: 1/2\n");
		    else if ((powerplay_flags2 & 0xe0) == 0x40)
			printf("\tdynamic clocking divider: 1/3\n");
		    else if ((powerplay_flags2 & 0xe0) == 0x60)
			printf("\tdynamic clocking divider: 1/4\n");
		    printf("\tdelay between voltage drop and sclk change: ");
		    if ((powerplay_flags2 & 0x700) == 0)
			printf("no delay\n");
		    else if ((powerplay_flags2 & 0x700) == 0x100)
			printf("33 us\n");
		    else if ((powerplay_flags2 & 0x700) == 0x200)
			printf("66 us\n");
		    else if ((powerplay_flags2 & 0x700) == 0x300)
			printf("99 us\n");
		    else if ((powerplay_flags2 & 0x700) == 0x400)
			printf("132 us\n");
		    if (powerplay_rev > 6) {
			int pcie_lanes;
			if (powerplay_flags2 & 0x800)
			    printf("\tperformance mode\n");
			if (powerplay_flags2 & 0x1000)
			    printf("\tvri-brightness required\n");
			pcie_lanes = BIOS8(powerplayoffset + 5 + (i * 0x10) + 0x10);
			if (pcie_lanes == 0)
			    pcie_lanes = 16;
			printf("\t%d pcie lanes\n", pcie_lanes);
		    }
		}
	    }
	}
	lcdddcoffset = BIOS16(offset+0x15);
	if (lcdddcoffset) {
	    int i2cline;
	    printf("LCD DDC table revision: %d\n", BIOS8(lcdddcoffset));
	    i2cline = BIOS8(lcdddcoffset+0x2);
	    printf("LCD DDC table i2c line: %d\n", i2cline);
	    if (i2cline > 4) {
		printf("LCD DDC table i2c clock pin mask: 0x%x\n", BIOS32(lcdddcoffset+0x3));
		printf("LCD DDC table i2c data pin mask: 0x%x\n", BIOS32(lcdddcoffset+0x7));
	    }
	}
	tmdspoweroffset = BIOS16(offset+0x17);
	if (tmdspoweroffset) {
	    int tmdsflags = BIOS8(tmdspoweroffset + 1);
	    int ontable_offset = BIOS16(tmdspoweroffset + 2);
	    int ontable_rev = BIOS8(ontable_offset);
	    int offtable_offset = BIOS16(tmdspoweroffset + 4);
	    int offtable_rev = BIOS8(offtable_offset);
	    printf("tmds power on/off table at offset: 0x%x\n", tmdspoweroffset);
	    printf("tmds power on/off table revision: %d\n", BIOS8(tmdspoweroffset));
	    if (tmdsflags & 1)
		printf("external tmds\n");
	    else
		printf("internal tmds\n");
	    printf("tmds power on table revision: %d\n", ontable_rev);
	    if (ontable_rev == 1) {
		// fix me
	    } else if (ontable_rev == 2) {
		int j = 4;
		int type;
		int blocks = BIOS8(ontable_offset + 3);
		int start = BIOS16(ontable_offset + j);
		int size = BIOS16(ontable_offset + 1);
		printf("tmds on table size: %d bytes\n", size);
		printf("tmds on table blocks: %d \n", blocks);
		while (blocks > 0) {
		    type = (start & 0xe000) >> 13;
		    if (type == 0) {
			unsigned int reg = BIOS16(ontable_offset + j) & 0x1fff;
			unsigned int val = BIOS32(ontable_offset + j + 2);
			printf("mmio reg: 0x%x, val: 0x%x\n", reg, val);
			j += 6;
		    } else if (type == 2) {
			unsigned int reg = BIOS16(ontable_offset + j) & 0x1fff;
			unsigned int and_mask = BIOS32(ontable_offset + j + 2);
			unsigned int or_mask = BIOS32(ontable_offset + j + 6);
			printf("mmio reg: 0x%x, AND mask: 0x%x, OR mask: 0x%x\n",
			       reg * 4, and_mask, or_mask);
			j += 10;
		    } else if (type == 3) {
			printf("delay %d ms\n", BIOS16(ontable_offset + j + 2));
			j += 4;
		    } else if (type == 4) {
			printf("delay %d us\n", BIOS16(ontable_offset + j + 2));
			j += 4;
		    } else if (type == 6) {
			int i2c_slave_addr = BIOS16(ontable_offset + j) & 0xff;
			int i2c_id = BIOS8(ontable_offset + j + 2);
			int i2c_reg = BIOS8(ontable_offset + j + 3);
			int i2c_reg_val = BIOS8(ontable_offset + j + 4);
			printf("write to i2c addr 0x%x (i2c id %d) reg: 0x%x, val: 0x%x\n",
			       i2c_slave_addr, i2c_id, i2c_reg, i2c_reg_val);
			j += 5;
		    } else
			break;
		    blocks--;;
		    start = BIOS16(ontable_offset + j);
		}
	    }
	    printf("tmds power off table revision: %d\n", offtable_rev);
	    if (offtable_rev == 1) {
		// fix me
	    } else if (offtable_rev == 2) {
		int j = 4;
		int type;
		int blocks = BIOS8(offtable_offset + 3);
		int start = BIOS16(offtable_offset + j);
		int size = BIOS16(offtable_offset + 1);
		printf("tmds off table size: %d bytes\n", size);
		printf("tmds off table blocks: %d \n", blocks);
		while (blocks > 0) {
		    type = (start & 0xe000) >> 13;
		    if (type == 0) {
			unsigned int reg = BIOS16(offtable_offset + j) & 0x1fff;
			unsigned int val = BIOS32(offtable_offset + j + 2);
			printf("mmio reg: 0x%x, val: 0x%x\n", reg, val);
			j += 6;
		    } else if (type == 2) {
			unsigned int reg = BIOS16(offtable_offset + j) & 0x1fff;
			unsigned int and_mask = BIOS32(offtable_offset + j + 2);
			unsigned int or_mask = BIOS32(offtable_offset + j + 6);
			printf("pll reg: 0x%x, AND mask: 0x%x, OR mask: 0x%x\n",
			       reg * 4, and_mask, or_mask);
			j += 10;
		    } else if (type == 3) {
			printf("delay %d ms\n", BIOS16(offtable_offset + j + 2));
			j += 4;
		    } else if (type == 4) {
			printf("delay %d us\n", BIOS16(offtable_offset + j + 2));
			j += 4;
		    } else if (type == 6) {
			int i2c_slave_addr = BIOS16(offtable_offset + j) & 0xff;
			int i2c_id = BIOS8(offtable_offset + j + 2);
			int i2c_reg = BIOS8(offtable_offset + j + 3);
			int i2c_reg_val = BIOS8(offtable_offset + j + 4);
			printf("write to i2c addr 0x%x (i2c id %d) reg: 0x%x, val: 0x%x\n",
			       i2c_slave_addr, i2c_id, i2c_reg, i2c_reg_val);
			j += 5;
		    } else
			break;
		    blocks--;
		    start = BIOS16(offtable_offset + j);
		}
	    }
	}
	if (rev > 7) {
		int external_ss_table = BIOS16(offset+0x15);
		if (external_ss_table) {
			printf("External SS table present %d\n", external_ss_table);
			printf("revision %d size bytes %d block %d\n", BIOS8(external_ss_table), BIOS8(external_ss_table + 1), BIOS8(external_ss_table + 2));

			printf("header bytes %d\n", BIOS8(external_ss_table + 3));
		}
		
	}
}

static void radeon_rom_legacy_dfptable(unsigned char *bios, int hdr)
{
	int offset, i, n, rev, stride;

	offset = BIOS16(hdr + 0x34);
	if (offset == 0) {
		printf("No DFP info table\n");
		return;
	}
	rev = BIOS8(offset);
	printf("DFP table revision: %d\n", rev);

	switch(rev) {
	case 3:
		n = BIOS8(offset + 5) + 1;
		if (n > 4)
			n = 4;
		for (i = 0; i < n; i++) {
			/* Looks weird ... but that's what is in X.org */
			printf("  PixClock: %f\t TMDS_PLL_CNTL: %08x\n",
			       BIOS16(offset+i*10+0x10) / 100.0,
			       BIOS32(offset+i*10+0x08));
		}
		break;

	/* revision 4 has some problem as it appears in RV280...
	 */
	case 4:
		stride = 0;
		n = BIOS8(offset+ 5) + 1;
		if (n > 4)
			n = 4;
		for (i = 0; i < n; i++) {
			printf("  PixClock: %f\t TMDS_PLL_CNTL: %08x\n",
			       BIOS16(offset+stride+0x10) / 100.0,
			       BIOS32(offset+stride+0x08));
			if (i == 0)
				stride += 10;
			else
				stride += 6;
		}
		break;
	}
}

static void radeon_rom_legacy_crttable(unsigned char *bios, int hdr)
{
	int offset, rev, dac2table, dac2muxreg, bgadjcrt1, dacwhitecrt1, bgadjcrt2, dacadjcrt2, temp;
	
	offset = BIOS16(hdr + 0x60);
	if (offset == 0) {
		printf("No CRT info table\n");
		return;
	}
	rev = BIOS8(offset) & 0x3;
	printf("\nCRT table revision: %d\n", rev);

	printf("\nCRT table size: %d bytes\n", BIOS8(offset+1));

	if (rev == 2) {

	    bgadjcrt1 = BIOS8(offset + 0x2);
	    dacwhitecrt1 = BIOS8(offset + 0x3);
	    printf("crt1: 0x%x, 0x%x\n", bgadjcrt1, dacwhitecrt1);

	    bgadjcrt2 = BIOS8(offset + 0x4);
	    dacadjcrt2 = BIOS8(offset + 0x5);
	    printf("crt2: 0x%x, 0x%x\n", bgadjcrt2, dacadjcrt2);

	    dac2table = BIOS16(offset+8); 

	} else {

	    bgadjcrt1 = BIOS8(offset + 0x2) & 0xf;
	    dacwhitecrt1 = (BIOS8(offset + 0x2) >> 4) & 0xf;
	    printf("crt1: 0x%x, 0x%x\n", bgadjcrt1, dacwhitecrt1);

	    bgadjcrt2 = BIOS8(offset + 0x3) & 0xf;
	    dacadjcrt2 = (BIOS8(offset + 0x3) >> 4) & 0xf;
	    printf("crt2: 0x%x, 0x%x\n", bgadjcrt2, dacadjcrt2);

	    dac2table = BIOS16(offset + 0x5); 
	}

	printf("reg val 0x%x\n", (bgadjcrt2 << 16) | (dacadjcrt2 << 20));

	if (dac2table) {
	    printf("\nDac2 table: 0x%x\n", dac2table);
	    printf("revision: %d\n", (BIOS16(dac2table) & 0x3));
	    dac2muxreg = BIOS16(dac2table + 0x2);
	    printf("\nmux reg: 0x%x\n", dac2muxreg);
	    temp = BIOS8(dac2table + 0x4);
	    if (temp & 0x80)
		printf("CRT2 active high\n");
	    else
		printf("CRT2 active low\n");

	    printf("pin detection bits: 0x%x\n", (temp & 0x1f));
	    printf("access mode: 0x%x\n", ((temp >> 5) & 0x3));

	}

}

static void radeon_rom_legacy_list_tables_present(unsigned char *bios, int hdr)
{
    int offset;

    offset = BIOS16(hdr + 0xc);
    if (offset) {
	printf("asic init table 1\n");
    }
    offset = BIOS16(hdr + 0x14);
    if (offset) {
	printf("bios support info table\n");
    }
    offset = BIOS16(hdr + 0x2a);
    if (offset) {
	printf("dac programming info table\n");
    }
    offset = BIOS16(hdr + 0x2c);
    if (offset) {
	printf("max color depth info table\n");
    }
    offset = BIOS16(hdr + 0x2e);
    if (offset) {
	printf("crtc info table\n");
    }
    offset = BIOS16(hdr + 0x30);
    if (offset) {
	printf("pll info table\n");
    }
    offset = BIOS16(hdr + 0x32);
    if (offset) {
	printf("TV info table\n");
    }
    offset = BIOS16(hdr + 0x34);
    if (offset) {
	printf("DFP info table\n");
    }
    offset = BIOS16(hdr + 0x36);
    if (offset) {
	printf("HW config info table\n");
    }
    offset = BIOS16(hdr + 0x38);
    if (offset) {
	printf("multimedia info table\n");
    }
    offset = BIOS16(hdr + 0x3e);
    if (offset) {
	printf("tv standard patch table\n");
    }
    offset = BIOS16(hdr + 0x40);
    if (offset) {
	printf("LCD info table\n");
    }
    offset = BIOS16(hdr + 0x42);
    if (offset) {
	printf("Mobile info table\n");
    }
    offset = BIOS16(hdr + 0x46);
    if (offset) {
	printf("pll init info table\n");
    }
    offset = BIOS16(hdr + 0x48);
    if (offset) {
	int check_offset = offset;
	printf("mem config info table\n");
	while (BIOS8(check_offset++));
	check_offset += 2;
	if (check_offset)
		printf("mem ram reset table %d %x %x\n", check_offset, BIOS8(check_offset -2), BIOS8(check_offset - 1));
    }
    offset = BIOS16(hdr + 0x4a);
    if (offset) {
	printf("save mask info table\n");
    }
    offset = BIOS16(hdr + 0x4c);
    if (offset) {
	printf("Hardcoded DFP edid\n");
    }
    offset = BIOS16(hdr + 0x4e);
    if (offset) {
	printf("asic init table 2\n");
    }
    offset = BIOS16(hdr + 0x50);
    if (offset) {
	printf("connector info table\n");
    }
    offset = BIOS16(hdr + 0x52);
    if (offset) {
	printf("dyn clock 1 info table\n");
    }
    offset = BIOS16(hdr + 0x54);
    if (offset) {
	printf("reserved mem info table\n");
    }
    offset = BIOS16(hdr + 0x58);
    if (offset) {
	printf("Ext TMDS info table\n");
    }
    offset = BIOS16(hdr + 0x5a);
    if (offset) {
	printf("mem clock info table\n");
    }
    offset = BIOS16(hdr + 0x5c);
    if (offset) {
	printf("ext DAC info table\n");
    }
    offset = BIOS16(hdr + 0x5e);
    if (offset) {
	printf("misc info table\n");
    }
    offset = BIOS16(hdr + 0x60);
    if (offset) {
	printf("CRT info table\n");
    }
    offset = BIOS16(hdr + 0x62);
    if (offset) {
	printf("integrated system info table\n");
    }
    offset = BIOS16(hdr + 0x64);
    if (offset) {
	printf("Component video info table\n");
    }
    offset = BIOS16(hdr + 0x66);
    if (offset) {
	printf("fan speed info table\n");
    }
    offset = BIOS16(hdr + 0x68);
    if (offset) {
	printf("overdrive info table\n");
    }
    offset = BIOS16(hdr + 0x6a);
    if (offset) {
	printf("OEM info table\n");
    }
    offset = BIOS16(hdr + 0x6c);
    if (offset) {
	printf("dyn clock 2 info table\n");
    }
    offset = BIOS16(hdr + 0x6e);
    if (offset) {
	printf("power connector info table\n");
    }
    offset = BIOS16(hdr + 0x70);
    if (offset) {
	printf("i2c info table\n");
    }
    offset = BIOS16(hdr + 0x72);
    if (offset) {
	printf("object header info table\n\n");
    }
    printf("\n");
}

static void radeon_rom_legacy_biosinfotable(unsigned char *bios, int hdr)
{
    int offset, i;
    char strp[4];

    offset = BIOS16(hdr + 0x14);
    if (offset == 0) {
	printf("bios info table\n");
	return;
    }
    printf("bios info table\n");
    for (i = 0; i < 4; i++)
	strp[i] = BIOS8(offset + i);
    printf("chip type: %s\n", strp);
    for (i = 0; i < 4; i++)
	strp[i] = BIOS32(offset + 4 + i);
    printf("bus type: %s\n", strp);
    for (i = 0; i < 4; i++)
	strp[i] = BIOS32(offset + 8 + i);
    printf("mem type: %s\n", strp);


}

static void radeon_rom_legacy_miscinfotable(unsigned char *bios, int hdr)
{
    int offset, rev, start, size;

    offset = BIOS16(hdr + 0x5e);
    if (offset == 0) {
	printf("No misc info table\n");
	return;
    }
    rev = BIOS8(offset);
    printf("misc info table revision: %d\n", rev);
    if (rev > 0) {
	size = BIOS8(offset + 2);
	printf("misc info table size: %d bytes\n", size);

    }
    start = BIOS8(offset + 1);
    if (start & 0x1)
	printf("dualview supported\n");
    if (rev == 8)
	if (start & 0x8)
	    printf("sleep mode enabled in perfomance mode\n");
    if (start & 0x20)
	printf("hypermemory flag\n");
    if (rev == 5) {
	if (start & 0x40)
	    printf("sleep mode enabled in perfomance mode\n");
    } else if (rev == 8) {
	if (start & 0x40)
	    printf("power state load balancing is enabled in perfomance mode\n");
    }
    if (rev == 6)
	if (start & 0x80)
	    printf("WMI thermal method supported\n");
    if (rev > 0) {
        if (BIOS16(offset + 0x3)) {
	    printf("asic init table 3 offset: 0x%x\n", BIOS16(offset + 0x3));
	    radeon_rom_legacy_mmio_table(bios, BIOS16(offset + 0x3));
	}
	if (BIOS16(offset + 0x5)) {
	    printf("asic init table 4 offset: 0x%x\n", BIOS16(offset + 0x5));
	    radeon_rom_legacy_mmio_table(bios, BIOS16(offset + 0x5));
	}
	if (BIOS16(offset + 0x7))
	    printf("detected mem config table offset: 0x%x\n", BIOS16(offset + 0x7));
	if (rev == 2) {
	    if (BIOS16(offset + 0x9))
		printf("asic init table 5 offset: 0x%x\n", BIOS16(offset + 0x9));
	    if (BIOS16(offset + 0xb))
		printf("memreset sequence table offset: 0x%x\n", BIOS16(offset + 0xb));
	} else if ((rev == 4) || (rev == 5) || (rev == 6)) {
	    if (BIOS16(offset + 0x9))
		printf("pointer to asic init table 5 offset list: 0x%x\n", BIOS16(offset + 0x9));
	    if (BIOS16(offset + 0xb))
		printf("pointer to memreset sequence table offset list: 0x%x\n", BIOS16(offset + 0xb));
	}
	if ((rev == 5) || (rev == 6)) {
	    if (BIOS16(offset + 0xd))
		printf("mem info table offset: 0x%x\n", BIOS16(offset + 0xd));
	    printf("min backlight value: 0x%x\n", BIOS8(offset + 0xf));
	}
	if (rev == 7) {
	    if (BIOS16(offset + 0x7))
		printf("pointer to detected mem config table offset list: 0x%x\n", BIOS16(offset + 0x7));
	    if (BIOS16(offset + 0x9))
		printf("pointer to asic init table 5 offset list: 0x%x\n", BIOS16(offset + 0x9));
	    if (BIOS16(offset + 0xb))
		printf("pointer to memreset sequence table offset list: 0x%x\n", BIOS16(offset + 0xb));
	}
	if (rev >= 6) {
	    int flags = BIOS8(offset + 0x10);
	    if (flags & 0x1)
		printf("driver controls brightness\n");
	    if (flags & 0x2)
		printf("bios controls powerplay\n");
	    if (flags & 0x4)
		printf("use new mem reset sequence\n");
	    if (flags & 0x8)
		printf("power state load balancing is disabled in performance mode\n");
	    if (rev == 9)
		if (flags & 0x40)
		    printf("PCIE to PCI bridge present\n");
	}

    }
}

static void radeon_rom_legacy_ram_reset_table(unsigned char *bios, int hdr)
{
	int offset = BIOS16(hdr + 0x48);
	uint32_t val;

	if (!offset)
		return;

	while (BIOS8(offset++));
	offset += 2;

	printf("ram reset table %d rev %d and mask %x\n", offset, BIOS8(offset - 1), BIOS8(offset - 2));
	val = BIOS8(offset);
	while(val != 0xff) {
		offset++;
		if (val == 0x0f) {
			printf("pwup complete test\n");
		} else {
			uint32_t or_mask = BIOS16(offset);
			offset+=2;
			printf("rmw SDRAM mask %x %x\n", or_mask, val);
		}
		val = BIOS8(offset);
	}
}

static void radeon_rom_legacy_mmio_table(unsigned char *bios, int offset)
{
	if (!offset)
		return;

	while (BIOS16(offset)) {
		uint16_t cmd = (BIOS16(offset) & 0xe000) >> 13;
		uint32_t addr = BIOS16(offset) & 0x1fff;
		uint32_t val, and_mask, or_mask, tmp;

		offset+=2;
		switch(cmd) {
		case 0:
		case 1:
			val = BIOS32(offset);
			offset += 4;
			printf("write reg %x %x\n", addr, val);
			break;
		case 2:
		case 3:
			and_mask = BIOS32(offset);
			offset += 4;
			or_mask = BIOS32(offset);
			offset += 4;
			printf("write reg %x and %x or %x val\n",
			       addr, and_mask, or_mask);
			break;
		case 4:
			val = BIOS16(offset);
			offset += 2;
			printf("delay %x\n", val);
			break;
		case 5:
			val = BIOS16(offset);
			offset += 2;
			switch (addr) {
			case 8:
				printf("wait for CLK_PWRMGR CNTL MC busy %x\n", val);
				break;
			case 9:
				printf("wait for MC_STATUS MC idle %x\n", val);
				break;
			}
			break;
		default:
			printf("unknown\n");
		}
	}
}


static void radeon_rom_legacy_asicinittable(unsigned char *bios, int hdr)
{
	int offset = BIOS16(hdr + 0xc);
	if (offset) {
		printf("asic init table 1\n");
		radeon_rom_legacy_mmio_table(bios, offset);
	}

	offset = BIOS16(hdr + 0x4e);
	if (offset) {
		printf("-----------------\n");
		printf("asic init table 2\n");
		radeon_rom_legacy_mmio_table(bios, offset);
	}
}

static void radeon_rom_legacy_plltable(unsigned char *bios, int offset)
{
	int type, start, i = 0;
	start = BIOS8(offset);
	while (start != 0) {
		type = (start & 0xc0) >> 6;
		if (type == 0) {
			int reg = BIOS8(offset + i) & 0x3f;
			unsigned int val = BIOS32(offset + i + 1);
			printf("pll reg: 0x%x, val: 0x%x\n", reg, val);
			i += 5;
		} else if (type == 1) {
			int reg = BIOS8(offset + i) & 0x3f;
			int byte_offset = BIOS8(offset + i + 1);
			int and_mask = BIOS8(offset + i + 2);
			int or_mask  = BIOS8(offset + i + 3);
			printf("pll reg: 0x%x, byte offset of dword 0x%x, AND mask: 0x%x, OR mask: 0x%x\n",
			       reg, byte_offset, and_mask, or_mask);
			i += 4;
		} else if (type >= 2) {
			int cmd = BIOS8(offset + i) & 0x3f;
			switch (cmd) {
			case 1:
				printf("delay 150 us\n");
				break;
			case 2:
				printf("delay 1 ms\n");
				break;
			case 3:
				printf("wait for MC_BUSY = 0 in CLK_PWRMGT_CNTL\n");
				break;
			case 4:
				printf("wait for DLL_READY = 1 in CLK_PWRMGT_CNTL\n");
				break;
			case 5:
				printf("check and set bit 24 in CLK_PWRMGT_CNTL to 0\n");
				break;
			default:
				printf("ass\n");
				break;
			}
			i += 1;
		} else
			break;
		start = BIOS8(offset + i);
	}
}

static void radeon_rom_legacy_dynclk1table(unsigned char *bios, int hdr)
{
	int offset, type, start, i = 0;

	offset = BIOS16(hdr + 0x52);
	if (offset == 0) {
		printf("No dyn clock 1 info table\n");
		return;
	}
	printf("dyn clock 1 info table\n");
	radeon_rom_legacy_plltable(bios, offset);
}

static void radeon_rom_legacy_pllinittable(unsigned char *bios, int hdr)
{
	int offset, type, start, i = 0;

	offset = BIOS16(hdr + 0x46);
	if (offset == 0) {
		return;
	}
	printf("pll init table %x\n", BIOS8(offset - 1));
	radeon_rom_legacy_plltable(bios, offset);
}
static void radeon_rom_legacy_dynclk2table(unsigned char *bios, int hdr)
{
    int offset, type, start, rev, i = 0;

    offset = BIOS16(hdr + 0x52);
    if (offset == 0) {
	printf("No dyn clock 2 info table\n");
	return;
    }
    rev = BIOS8(offset - 1);
    start = BIOS16(offset);
    printf("dyn clock 2 info table revision %d\n", rev);
    while (start != 0) {
	type = (start & 0xe000) >> 13;
	if (type == 0) {
	    unsigned int reg = BIOS16(offset + i) & 0x1fff;
	    unsigned int val = BIOS32(offset + i + 2);
	    printf("mmio reg: 0x%x, val: 0x%x\n", reg * 4, val);
	    i += 6;
	} else if (type == 1) {
	    unsigned int reg = BIOS16(offset + i) & 0x1fff;
	    unsigned int val = BIOS32(offset + i + 2);
	    printf("I/O reg: 0x%x, val: 0x%x\n", reg * 4, val);
	    i += 6;
	} else if (type == 2) {
	    unsigned int reg = BIOS16(offset + i) & 0x1fff;
	    unsigned int and_mask = BIOS32(offset + i + 2);
	    unsigned int or_mask = BIOS32(offset + i + 6);
	    printf("mmio reg: 0x%x, AND mask: 0x%x, OR mask: 0x%x\n",
		   reg * 4, and_mask, or_mask);
	    i += 10;
	} else if (type == 3) {
	    unsigned int reg = BIOS16(offset + i) & 0x1fff;
	    unsigned int and_mask = BIOS32(offset + i + 2);
	    unsigned int or_mask = BIOS32(offset + i + 6);
	    printf("I/O reg: 0x%x, AND mask: 0x%x, OR mask: 0x%x\n",
		   reg * 4, and_mask, or_mask);
	    i += 10;
	} else if (type == 4) {
	    printf("delay %d us\n", BIOS16(offset + i + 2));
	    i += 4;
	} else
	    break;
	start = BIOS16(offset + i);
    }
}

static void radeon_rom_legacy_igptable(unsigned char *bios, int hdr)
{
    int offset, rev, fsb;

	offset = BIOS16(hdr + 0x62);
	if (offset == 0) {
		printf("No igp info table\n");
		return;
	}
	rev = BIOS8(offset);
	printf("\nigp table revision: %d\n", rev);

	fsb = BIOS16(offset + 0x2);
	if (rev < 2)
	    fsb *= 100;
	printf("FSB: %f Mhz\n", fsb);

	printf("mclk reference frequency: %f Mhz\n", BIOS16(offset + 0x4) / 100.00);
	printf("mclk reference divider: %d \n", BIOS16(offset + 0x6));
	printf("memory refresh period from SPD: %d \n", BIOS8(offset + 0x8));
	if (rev > 0)
	    printf("min mclk: %f \n", BIOS16(offset + 0xd) / 100.00);
	if (rev > 1)
	    printf("max mclk: %f \n", BIOS16(offset + 0xf) / 100.00);
	if (rev > 2) {
	    printf("K8 mclk: %f \n", BIOS16(offset + 0x11));
	    printf("K8 sync start delay: %f us\n", BIOS16(offset + 0x13) / 100);
	    printf("K8 data return time: %f us\n", BIOS16(offset + 0x15) / 100);
	}
	if (rev > 3) {
	    if (BIOS16(offset + 0x17) & 1)
		printf("PCIE lane reserved\n");
	    else
		printf("PCIE lane not reserved\n");
	}
}

static void radeon_rom_legacy_componenttv_table(unsigned char *bios, int hdr)
{
    int offset, rev, temp;

	offset = BIOS16(hdr + 0x62);
	if (offset == 0) {
		printf("No component tv info table\n");
		return;
	}
	rev = BIOS8(offset);
	printf("\ncomponent tv table revision: %d\n", rev);

	if (rev < 3) {
	    if (BIOS8(offset + 0x2) & 0x4)
		printf("CRT2 Mux used as well to switch to CV\n");
	    if (BIOS8(offset + 0x2) & 0x8)
		printf("Low voltage TV/CV MUX control\n");
	} else {
	    if (BIOS8(offset + 0x2) & 0x10)
		printf("enable access for i2c D-Connect Support\n");
	}
	printf("GPIO register for detection: 0x%x \n", BIOS16(offset + 0x3));
	temp = BIOS8(offset + 0x5);
	if (temp & 0x80)
	    printf("Active high\n");
	else
	    printf("Active low\n");
	printf("GPIO TV/HDTV MUX control register: 0x%x \n", BIOS16(offset + 0x6));
	temp = BIOS8(offset + 0x8);
	if (temp & 0x80)
	    printf("Active high\n");
	else
	    printf("Active low\n");

}

static void radeon_rom_legacy_integratedtable(unsigned char *bios, int hdr)
{
	int offset, rev, size;

	offset = BIOS16(hdr + 0x62);
	if (offset == 0) {
		printf("no igp table\n");
		return;
	}

	rev = BIOS8(offset);
	size = BIOS8(offset + 1);

	printf("igp table rev %d size %d\n", rev, size);

	if (rev < 2)
		printf("FSB freq in Khz * 10 %d\n", BIOS16(offset + 2));
	else
		printf("FSB freq in Mhz %d\n", BIOS16(offset + 2));

	printf("Memory reference clock in Mhz * 100 %d\n", BIOS16(offset + 4));
	printf("Memory reference divider %d\n", BIOS16(offset + 6));

	if (rev >= 3) {
		printf("K8 memory clock %d\n", BIOS16(offset + 0x11));
	}
}

static void radeon_rom_legacy_multimediatable(unsigned char *bios, int hdr)
{
	int offset, rev, size;
	int tmp;

	offset = BIOS16(hdr + 0x38);
	if (offset == 0) {
		printf("no mm info table\n");
		return;
	}
	rev = BIOS8(offset - 2);
	size = BIOS8(offset - 1);

	printf("mm table rev %d size %d\n", rev, size);

	tmp = BIOS8(offset);
	printf("tuner id %x - video input %d\n", tmp & 0x1f,
	       (tmp >> 5) & 0x7);

	tmp = BIOS8(offset + 1);
	printf("audio chip %x\n", tmp & 0xf);
	printf("product %s - rev %d\n", tmp & 0x10 ? "ATI" : "OEM",
	       tmp >> 5);
	printf("product ID %d\n", BIOS8(offset + 2));
	
	tmp = BIOS8(offset + 3);
	printf("tuner regulator control %d\n", tmp & 0x3);
	printf("teletext support %d\n", (tmp >> 2) & 0x3);
	printf("fm audio decoder %d\n", (tmp >> 4) & 0x3);
	printf("audio scramming %d\n", tmp >> 7);

	tmp = BIOS8(offset + 4);
	printf("i2s input config %d, output config %d\n", tmp & 0x1,
	       (tmp >> 1) & 0x1);
	printf("i2s audio chip %d\n", (tmp >> 2) & 0x3);

	tmp = BIOS8(offset + 5);
	printf("video decoder type %x\n", tmp & 0xf);
	printf("video crystal %d\n", (tmp >> 4) & 0xf);
	
	tmp = BIOS8(offset + 6);
	printf("video decoder config %d\n", tmp);
}



static void radeon_rom_legacy_i2ctable(unsigned char *bios, int hdr)
{
    int offset, rev, size, blocks, i, id, reg, clock, data;

	offset = BIOS16(hdr + 0x70);
	if (offset == 0) {
		printf("No i2c info table\n");
		return;
	}
	rev = BIOS8(offset);
	printf("\ni2c table revision: %d\n", rev);
	size = BIOS8(offset + 1);
	printf("i2c table size: %d\n", size);

	blocks = BIOS8(offset + 2);
	printf("i2c blocks: %d\n", blocks);

	for (i = 0; i < blocks; i++) {
	    id = BIOS8(offset + 3 + (i * 5) + 0);
	    reg = BIOS16(offset + 3 + (i * 5) + 1);
	    clock = BIOS8(offset + 3 + (i * 5) + 3);
	    data = BIOS8(offset + 3 + (i * 5) + 4);
	    printf("id: %d, reg: 0x%x, clk: %d, data: %d\n", id, reg * 4, clock, data);
	}

}

static void radeon_rom_legacy_tvtable(unsigned char *bios, int hdr)
{
	int offset, rev, refclk, drvstds, biosstds;
	
	offset = BIOS16(hdr + 0x32);
	if (offset == 0) {
		printf("No TV info table\n");
		return;
	}
	rev = BIOS8(offset + 3);
	printf("\nTV table revision: %d\n", rev);


	printf("\nTV table size: %d\n", BIOS16(offset + 4));

	if (BIOS8(offset + 6) == 'T')
	    printf("TV out on board\n");
	else
	    printf("No TV out on board\n");

	printf("Default Standard: ");
	switch (BIOS8(offset + 7)) {
	case 1:
	    printf("NTSC\n");
	    break;
	case 2:
	    printf("PAL\n");
	    break;
	case 3:
	    printf("PAL-M\n");
	    break;
	case 4:
	    printf("PAL-60\n");
	    break;
	case 5:
	    printf("NTSC-J\n");
	    break;
	case 6:
	    printf("SCART-PAL\n");
	    break;
	default:
	    printf("Unknown standard\n");
            break;
	}

	printf("TV Ref Clk: ");
	refclk = BIOS8(offset + 9) >> 2;
	if (refclk == 0)
	    printf("29.498928713 MHz\n");
	else if (refclk == 1)
	    printf("28.636360000 MHz\n");
	else if (refclk == 2)
	    printf("14.318180000 MHz\n");
	else if (refclk == 3)
	    printf("27.000000000 MHz\n");

	printf("TV standards supported by driver: ");
	drvstds = BIOS8(offset + 10);
	if (drvstds & 1)
	    printf("NTSC ");
	if (drvstds & 2)
	    printf("PAL ");
	if (drvstds & 4)
	    printf("PAL-M ");
	if (drvstds & 8)
	    printf("PAL-60 ");
	if (drvstds & 16)
	    printf("NTSC-J ");
	if (drvstds & 32)
	    printf("SCART-PAL");
	printf("\n");

	printf("TV standards supported by bios: ");
	biosstds = BIOS8(offset + 11);
	if (biosstds & 1)
	    printf("NTSC ");
	if (biosstds & 2)
	    printf("PAL ");
	if (biosstds & 4)
	    printf("PAL-M ");
	if (biosstds & 8)
	    printf("PAL-60 ");
	if (biosstds & 16)
	    printf("NTSC-J ");
	if (biosstds & 32)
	    printf("SCART-PAL");
	printf("\n");

	if (rev >= 5) {
	    int temp, temp2;

	    temp = BIOS8(offset + 0xc);
	    temp2 = BIOS8(offset + 0xd);
	    printf("crt2 ps2: 0x%x, 0x%x\n", temp, temp2);

	    temp = BIOS8(offset + 0xe);
	    temp2 = BIOS8(offset + 0xf);
	    printf("crt2 pal: 0x%x, 0x%x\n", temp, temp2);

	    temp = BIOS8(offset + 0x10);
	    temp2 = BIOS8(offset + 0x11);
	    printf("crt2 ntsc: 0x%x, 0x%x\n", temp, temp2);

	    temp = BIOS16(offset + 0x12);
	    printf("gpio reg: 0x%x\n", temp);

	    temp = BIOS16(offset + 0x14);
	    printf("gpio AND mask: 0x%x\n", temp);

	    temp = BIOS16(offset + 0x18);
	    printf("gpio OR mask: 0x%x\n", temp);

	} else if (rev >= 2) {
	    int temp, temp2;

	    temp = BIOS8(offset + 0xc) & 0xf;
	    temp2 = (BIOS8(offset + 0xc) >> 4) & 0xf;
	    printf("crt2 ps2: 0x%x, 0x%x\n", temp, temp2);

	    temp = BIOS8(offset + 0xd) & 0xf;
	    temp2 = (BIOS8(offset + 0xd) >> 4) & 0xf;
	    printf("crt2 pal: 0x%x, 0x%x\n", temp, temp2);

	    temp = BIOS8(offset + 0xe) & 0xf;
	    temp2 = (BIOS8(offset + 0xe) >> 4) & 0xf;
	    printf("crt2 ntsc: 0x%x, 0x%x\n", temp, temp2);

	    if (rev > 2) {
		temp = BIOS8(offset + 0x10);
		printf("gpio bit: 0x%x\n", temp);
	    }

	    if (rev > 3) {
		temp = BIOS16(offset + 0x11);
		printf("gpio reg: 0x%x\n", temp);
	    }

	}


}

static void radeon_rom_legacy_exttmdstable(unsigned char *bios, int hdr)
{
	int offset, rev;
	int nr_blocks;
	int table_start;
	unsigned short index;
	unsigned short id;
	offset = BIOS16(hdr + 0x58);
	if (offset == 0) {
		printf("No External TMDS table found\n");
		return;
	}

	rev = BIOS8(offset);

	printf("Found External TMDS Table rev %d\n", rev);

	if (rev == 2)
	    printf("single link\n");
	else if (rev == 3)
	    printf("dual link\n");

	printf("table size %08x\n", BIOS16(offset+1));


	nr_blocks = BIOS8(offset+3);

	printf("no blocks %08x\n", nr_blocks);

	table_start = offset+4;
	printf("max freq %d, slave i2c %02x i2c %d conn id %d, flags %d\n",
	       BIOS16(table_start), BIOS8(table_start+2), BIOS8(table_start+3),
	       BIOS8(table_start+4), BIOS8(table_start+5));

	index = table_start+6;
	printf("next short is %04X\n", BIOS16(index)>>13);

	id = BIOS16(index);
	printf("id is %04X %d\n", id, id & 0x1fff);

	while (id != 0xffff) {
	       switch(id >> 13) {
	       case 0:
		       printf("mm write\n");
		       index += 6;
		       break;
	       case 2:
		       printf("mm mask write\n");
		       index += 10;
		       break;
	       case 4:
		       printf("delay microsec \n");
		       index += 4;
		       break;
	       case 5:
		       printf("pll mask write \n");
		       index += 10;
		       break;
	       case 6:
		       printf("i2c write %02X\n", BIOS8(index+2));
		       index += 3;
		       break;
	       default:
		       printf("unknown id %d\n", id>>13);
		       return;
	       };

	       id = BIOS16(index);
	       printf("id is %04X %d\n", id, id & 0x1fff);

	}
}

void radeon_rom_legacy_memclktable(unsigned char *bios, int hdr)
{ 
	int offset = BIOS16(hdr + 0x5a);
	int block_rev;
	if (!offset)
		return;

	block_rev = BIOS8(offset);
	while (block_rev != 0xff) {
		printf("mem clock table header %d\n", block_rev);
		if (block_rev == 1) {
			printf("mem clock min %d ,max %d\n", BIOS16(offset + 1), BIOS16(offset + 3));
			offset += 5;
		}
		if (block_rev == 2) {
			printf("pre mem clock reset table %d\n", BIOS16(offset + 1));
			offset += 3;
		}
		if (block_rev == 3) {
			printf("pll change table %d\n", BIOS16(offset + 1));
			offset += 3;
		}
		if (block_rev == 4) {
			printf("register change table %d\n", BIOS16(offset + 1));
			offset += 3;
		}
		if (block_rev == 5) {
			printf("post memory clock reset seq table %d\n", BIOS16(offset + 1));
			offset += 3;
		}
		if (block_rev == 6) {
			printf("mc register change table %d\n", BIOS16(offset + 1));
			offset += 3;
		}
		if (block_rev == 7) {
			printf("pll pre clock lock table %d\n", BIOS16(offset + 1));
			offset += 3;
		}
		if (block_rev == 8) {
			printf("pre clock change table %d\n", BIOS16(offset + 1));
			offset += 3;
		}
		if (block_rev == 9) {
			printf("post memory clock reset seq table 2 %d\n", BIOS16(offset + 1));
			offset += 3;
		}
		block_rev = BIOS8(offset);
	}
}

#define OF32(offset)	(*((unsigned int *)(bios + (offset))))
#define _2K (2*1024)

#define OF_TABLE_INIT1 1
#define OF_TABLE_INIT2 2
#define OF_TABLE_PLL 3
#define OF_TABLE_MEMINIT 4

void radeon_of_table(const char * file, int table)
{
	unsigned char bios[_2K];
	unsigned int reg, mask, val, op;
	int fd;
	int len;
	int count = 0;
	fd = open(file, O_RDONLY);
	if (fd < 0) {
		perror("can't open init file");
		return;
	}
	memset(bios, 0, _2K);
	len = read(fd, bios, _2K);
	close(fd);

	while (len > 0) {
		switch(table) {
		case OF_TABLE_INIT1:
			len -= 12;
			reg = OF32(count);
			mask = OF32(count + 4);
			val = OF32(count + 8);
			printf("reg: 0x%x, mask 0x%x, val 0x%x\n", reg, mask, val);
			count += 12;
			break;
		case OF_TABLE_INIT2:
			len -= 16;
			reg = OF32(count);
			mask = OF32(count + 4);
			val = OF32(count + 8);
			op = OF32(count + 12);
			printf("reg: 0x%x, mask 0x%x, val 0x%x op 0x%x\n", reg, mask, val, op);
			count += 16;
			break;
		case OF_TABLE_PLL:
			len -= 16;
			reg = OF32(count);
			mask = OF32(count + 4);
			val = OF32(count + 8);
			op = OF32(count + 12);
			printf("pll reg: 0x%x, mask 0x%x, val 0x%x, op %x\n", reg, mask, val, op);
			if (op == 5)
				printf("delay 1 ms\n");
			else if (op == 6)
				printf("delay 150 us\n");
			else if (op)
				printf("unknown op %d\n", op);
			count += 16;
			break;
		case OF_TABLE_MEMINIT:
			len -= 4;
			val = OF32(count);
			if (val >> 16 == 0x6fff)
				printf("pwup complete test\n");
			else {
				mask = val >> 24;
				val = val & 0xffff;
				printf("rmw SDRAM mask %x %x\n", val, mask);
			}
			count += 4;
			break;
		}
	}
}

void radeon_rom_tables(const char * file)
{
#define _64K (64*1024)
	unsigned char bios[_64K];
	int fd, hdr, atom;

	fd = open(file, O_RDONLY);
	if (fd < 0) {
		perror("can't open rom file");
		return;
	}
	memset(bios, 0, _64K);
	read(fd, bios, _64K);
	close(fd);

	if (bios[0] != 0x55 || bios[1] != 0xaa)
		die("PCI ROM signature 0x55 0xaa missing");
	hdr = BIOS16(0x48);
	printf("\nBIOS Tables:\n------------\n\n");	
	printf("Header at %x, type: %d [%s]\n", hdr, BIOS8(hdr),
	       radeon_valname(hdr_type_name, BIOS8(hdr)));
	printf("OEM ID: %02x %02x\n", BIOS8(hdr+2), BIOS8(hdr+3));
	atom = (BIOS8(hdr+4)   == 'A' &&
		BIOS8(hdr+5) == 'T' &&
		BIOS8(hdr+6) == 'O' &&
		BIOS8(hdr+7) == 'M') ||
		(BIOS8(hdr+4)   == 'M' &&
		 BIOS8(hdr+5) == 'O' &&
		 BIOS8(hdr+6) == 'T' &&
		 BIOS8(hdr+7) == 'A');
	if (atom) {
		int master = BIOS16(hdr+32);
		printf("ATOM BIOS detected !\n\n");
		radeon_rom_atom_clocks(bios, master);
		radeon_rom_atom_connectors(bios, master);
		// add more ...
	} else {
		printf("Legacy BIOS detected !\n");
		printf("BIOS Rev: %x.%x\n\n", BIOS8(hdr+4), BIOS8(hdr+5));
		radeon_rom_legacy_list_tables_present(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_asicinittable(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_pllinittable(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_ram_reset_table(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_clocks(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_connectors(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_dfptable(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_exttmdstable(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_tvtable(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_crttable(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_i2ctable(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_lcdtable(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_mobiletable(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_igptable(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_componenttv_table(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_dynclk1table(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_dynclk2table(bios, hdr);
		printf("-------------\n");
		radeon_rom_legacy_miscinfotable(bios, hdr);
                printf("-------------\n");
		radeon_rom_legacy_biosinfotable(bios, hdr);
                printf("-------------\n");
		radeon_rom_legacy_memclktable(bios, hdr);
                printf("-------------\n");
		radeon_rom_legacy_multimediatable(bios, hdr);
                printf("-------------\n");
		radeon_rom_legacy_integratedtable(bios, hdr);
                printf("-------------\n");
	}
}

int main(int argc,char *argv[]) 
{
    while (argc >= 2) {
        if(strcmp(argv[1],"--debug") == 0) {
            debug=1;
            argv++; argc--;
        } else if (strncmp(argv[1],"--skip=", 7) == 0) {
            skip=atoi(argv[1]+7);
            argv++; argc--;
        } else {
            break;
        }
    }
    if(argc == 2) {
    	map_radeon_cntl_mem();
        if(strcmp(argv[1],"regs") == 0) {
            radeon_cmd_regs();
            return 0;
        } else if(strcmp(argv[1],"bits") == 0) {
            radeon_cmd_bits();
            return 0;
        } else if(strcmp(argv[1],"dac") == 0) {
            radeon_cmd_dac(NULL);
            return 0;
        } else if(strcmp(argv[1],"light") == 0) {
            radeon_cmd_light(NULL);
            return 0;
        } else if(strcmp(argv[1],"stretch") == 0) {
            radeon_cmd_stretch(NULL);
            return 0;
        };
    } else if(argc == 3) {
        if(strcmp(argv[1],"romtables") == 0) {
		radeon_rom_tables(argv[2]);
		return 0;
	}
        if(strcmp(argv[1],"oftablepll") == 0) {
		radeon_of_table(argv[2], OF_TABLE_PLL);
		return 0;
	}
        if(strcmp(argv[1],"oftableinit1") == 0) {
		radeon_of_table(argv[2], OF_TABLE_INIT1);
		return 0;
	}
        if(strcmp(argv[1],"oftableinit2") == 0) {
		radeon_of_table(argv[2], OF_TABLE_INIT2);
		return 0;
	}
        if(strcmp(argv[1],"oftablememinit") == 0) {
		radeon_of_table(argv[2], OF_TABLE_MEMINIT);
		return 0;
	}
    	map_radeon_cntl_mem();
        if(strcmp(argv[1],"dac") == 0) {
            radeon_cmd_dac(argv[2]);
            return 0;
        } else if(strcmp(argv[1],"light") == 0) {
            radeon_cmd_light(argv[2]);
            return 0;
        } else if(strcmp(argv[1],"stretch") == 0) {
            radeon_cmd_stretch(argv[2]);
            return 0;
        } else if(strcmp(argv[1],"regmatch") == 0) {
            radeon_reg_match(argv[2]);
            return 0;
	}
    } else if(argc == 4) {
    	map_radeon_cntl_mem();
	if(strcmp(argv[1],"regset") == 0) {
	    radeon_reg_set(argv[2], strtoul(argv[3], NULL, 0));
	    return 0;
	}
    } else {
	map_radeon_cntl_mem();
    }

    usage();
    return 1;
}



