xenocara/driver/xf86-video-radeonhd/utils/conntest/rhd_conntest.c
2007-12-04 22:20:01 +00:00

1612 lines
43 KiB
C

/*
* Copyright 2007 Luc Verhaegen <lverhaegen@novell.com>
* Copyright 2007 Matthias Hopf <mhopf@novell.com>
* Copyright 2007 Egbert Eich <eich@novell.com>
* Copyright 2007 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* This tool is here to help create a connector mapping table.
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <pci/pci.h>
#include <unistd.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "git_version.h"
#ifndef ULONG
typedef unsigned int ULONG;
# define ULONG ULONG
#endif
#ifndef UCHAR
typedef unsigned char UCHAR;
# define UCHAR UCHAR
#endif
#ifndef USHORT
typedef unsigned short USHORT;
# define USHORT USHORT
#endif
#include "atombios.h"
typedef int Bool;
#define FALSE 0
#define TRUE 1
typedef unsigned char CARD8;
typedef unsigned short CARD16;
typedef unsigned int CARD32;
#define VBIOS_BASE 0xC0000
#define VBIOS_MAXSIZE 0x10000
#define DEV_MEM "/dev/mem"
#define TARGET_HW_I2C_CLOCK 25 /* kHz */
/* Some register names */
enum {
/* DAC A */
DACA_ENABLE = 0x7800,
DACA_SOURCE_SELECT = 0x7804,
DACA_AUTODETECT_CONTROL = 0x7828,
DACA_FORCE_OUTPUT_CNTL = 0x783C,
DACA_FORCE_DATA = 0x7840,
DACA_POWERDOWN = 0x7850,
DACA_CONTROL1 = 0x7854,
DACA_CONTROL2 = 0x7858,
DACA_COMPARATOR_ENABLE = 0x785C,
DACA_COMPARATOR_OUTPUT = 0x7860,
/* DAC B */
DACB_ENABLE = 0x7A00,
DACB_SOURCE_SELECT = 0x7A04,
DACB_AUTODETECT_CONTROL = 0x7A28,
DACB_FORCE_OUTPUT_CNTL = 0x7A3C,
DACB_FORCE_DATA = 0x7A40,
DACB_POWERDOWN = 0x7A50,
DACB_CONTROL1 = 0x7A54,
DACB_CONTROL2 = 0x7A58,
DACB_COMPARATOR_ENABLE = 0x7A5C,
DACB_COMPARATOR_OUTPUT = 0x7A60,
/* TMDSA */
TMDSA_CNTL = 0x7880,
TMDSA_SOURCE_SELECT = 0x7884,
TMDSA_COLOR_FORMAT = 0x7888,
TMDSA_FORCE_OUTPUT_CNTL = 0x788C,
TMDSA_BIT_DEPTH_CONTROL = 0x7894,
TMDSA_DCBALANCER_CONTROL = 0x78D0,
TMDSA_DATA_SYNCHRONIZATION_R500 = 0x78D8,
TMDSA_DATA_SYNCHRONIZATION_R600 = 0x78DC,
TMDSA_TRANSMITTER_ENABLE = 0x7904,
TMDSA_LOAD_DETECT = 0x7908,
TMDSA_MACRO_CONTROL = 0x790C, /* r5x0 and r600: 3 for pll and 1 for TX */
TMDSA_PLL_ADJUST = 0x790C, /* rv6x0: pll only */
TMDSA_TRANSMITTER_CONTROL = 0x7910,
TMDSA_TRANSMITTER_ADJUST = 0x7920, /* rv6x0: TX part of macro control */
/* LVTMA */
LVTMA_CNTL = 0x7A80,
LVTMA_SOURCE_SELECT = 0x7A84,
LVTMA_BIT_DEPTH_CONTROL = 0x7A94,
LVTMA_DATA_SYNCHRONIZATION = 0x7AD8,
LVTMA_PWRSEQ_REF_DIV = 0x7AE4,
LVTMA_PWRSEQ_DELAY1 = 0x7AE8,
LVTMA_PWRSEQ_DELAY2 = 0x7AEC,
LVTMA_PWRSEQ_CNTL = 0x7AF0,
LVTMA_PWRSEQ_STATE = 0x7AF4,
LVTMA_LVDS_DATA_CNTL = 0x7AFC,
LVTMA_MODE = 0x7B00,
LVTMA_TRANSMITTER_ENABLE = 0x7B04,
LVTMA_MACRO_CONTROL = 0x7B0C,
LVTMA_TRANSMITTER_CONTROL = 0x7B10,
/* I2C */
/* R5XX */
R5_DC_I2C_STATUS1 = 0x7D30,
R5_DC_I2C_RESET = 0x7D34,
R5_DC_I2C_CONTROL1 = 0x7D38,
R5_DC_I2C_CONTROL2 = 0x7D3C,
R5_DC_I2C_CONTROL3 = 0x7D40,
R5_DC_I2C_DATA = 0x7D44,
R5_DC_I2C_INTERRUPT_CONTROL = 0x7D48,
R5_DC_I2C_ARBITRATION = 0x7D50,
/* R6XX */
R6_DC_I2C_CONTROL = 0x7D30, /* (RW) */
R6_DC_I2C_ARBITRATION = 0x7D34, /* (RW) */
R6_DC_I2C_INTERRUPT_CONTROL = 0x7D38, /* (RW) */
R6_DC_I2C_SW_STATUS = 0x7d3c, /* (RW) */
R6_DC_I2C_DDC1_SPEED = 0x7D4C, /* (RW) */
R6_DC_I2C_DDC1_SETUP = 0x7D50, /* (RW) */
R6_DC_I2C_DDC2_SPEED = 0x7D54, /* (RW) */
R6_DC_I2C_DDC2_SETUP = 0x7D58, /* (RW) */
R6_DC_I2C_DDC3_SPEED = 0x7D5C, /* (RW) */
R6_DC_I2C_DDC3_SETUP = 0x7D60, /* (RW) */
R6_DC_I2C_TRANSACTION0 = 0x7D64, /* (RW) */
R6_DC_I2C_TRANSACTION1 = 0x7D68, /* (RW) */
R6_DC_I2C_DATA = 0x7D74, /* (RW) */
R6_DC_I2C_DDC4_SPEED = 0x7DB4, /* (RW) */
R6_DC_I2C_DDC4_SETUP = 0x7DBC, /* (RW) */
DC_GPIO_DDC4_MASK = 0x7E00, /* (RW) */
DC_GPIO_DDC4_A = 0x7E04, /* (RW) */
DC_GPIO_DDC4_EN = 0x7E08, /* (RW) */
DC_GPIO_DDC1_MASK = 0x7E40, /* (RW) */
DC_GPIO_DDC1_A = 0x7E44, /* (RW) */
DC_GPIO_DDC1_EN = 0x7E48, /* (RW) */
DC_GPIO_DDC1_Y = 0x7E4C, /* (RW) */
DC_GPIO_DDC2_MASK = 0x7E50, /* (RW) */
DC_GPIO_DDC2_A = 0x7E54, /* (RW) */
DC_GPIO_DDC2_EN = 0x7E58, /* (RW) */
DC_GPIO_DDC2_Y = 0x7E5C, /* (RW) */
DC_GPIO_DDC3_MASK = 0x7E60, /* (RW) */
DC_GPIO_DDC3_A = 0x7E64, /* (RW) */
DC_GPIO_DDC3_EN = 0x7E68, /* (RW) */
DC_GPIO_DDC3_Y = 0x7E6C, /* (RW) */
/* RS69x I2C */
RS69_DC_I2C_CONTROL = 0x7D30, /* (RW) */
RS69_DC_I2C_UNKNOWN_2 = 0x7D34, /* (RW) */
RS69_DC_I2C_INTERRUPT_CONTROL = 0x7D38, /* (RW) */
RS69_DC_I2C_SW_STATUS = 0x7d3c, /* (RW) */
RS69_DC_I2C_UNKNOWN_1 = 0x7d40,
RS69_DC_I2C_DDC_SETUP_Q = 0x7D44, /* (RW) */
RS69_DC_I2C_DATA = 0x7D58, /* (RW) */
RS69_DC_I2C_TRANSACTION0 = 0x7D48, /* (RW) */
RS69_DC_I2C_TRANSACTION1 = 0x7D4C, /* (RW) */
/* HPD */
DC_GPIO_HPD_Y = 0x7E9C
};
typedef enum _chipType {
RHD_R500 = 1,
RHD_RS690,
RHD_R600
} chipType;
/* for RHD_R500/R600 */
chipType ChipType;
typedef struct _tableVersion
{
CARD8 crev;
CARD8 frev;
} tableVersion;
typedef struct _atomDataTables
{
union {
void *base;
ATOM_FIRMWARE_INFO *FirmwareInfo;
ATOM_FIRMWARE_INFO_V1_2 *FirmwareInfo_V_1_2;
ATOM_FIRMWARE_INFO_V1_3 *FirmwareInfo_V_1_3;
ATOM_FIRMWARE_INFO_V1_4 *FirmwareInfo_V_1_4;
} FirmwareInfo;
tableVersion FirmwareInfoVersion;
ATOM_GPIO_I2C_INFO *GPIO_I2C_Info;
tableVersion GPIO_I2C_InfoVersion;
} atomDataTables, *atomDataTablesPtr;
atomDataTables AtomData;
/*
* Match pci ids against data and some callbacks
*/
struct RHDDevice {
CARD16 vendor;
CARD16 device;
int bar;
chipType type;
} rhdDevices[] = {
{ 0x1002, 0x7100, 2, RHD_R500},
{ 0x1002, 0x7101, 2, RHD_R500},
{ 0x1002, 0x7102, 2, RHD_R500},
{ 0x1002, 0x7103, 2, RHD_R500},
{ 0x1002, 0x7104, 2, RHD_R500},
{ 0x1002, 0x7105, 2, RHD_R500},
{ 0x1002, 0x7106, 2, RHD_R500},
{ 0x1002, 0x7108, 2, RHD_R500},
{ 0x1002, 0x7109, 2, RHD_R500},
{ 0x1002, 0x710A, 2, RHD_R500},
{ 0x1002, 0x710B, 2, RHD_R500},
{ 0x1002, 0x710C, 2, RHD_R500},
{ 0x1002, 0x710E, 2, RHD_R500},
{ 0x1002, 0x710F, 2, RHD_R500},
{ 0x1002, 0x7140, 2, RHD_R500},
{ 0x1002, 0x7141, 2, RHD_R500},
{ 0x1002, 0x7142, 2, RHD_R500},
{ 0x1002, 0x7143, 2, RHD_R500},
{ 0x1002, 0x7144, 2, RHD_R500},
{ 0x1002, 0x7145, 2, RHD_R500},
{ 0x1002, 0x7146, 2, RHD_R500},
{ 0x1002, 0x7147, 2, RHD_R500},
{ 0x1002, 0x7149, 2, RHD_R500},
{ 0x1002, 0x714A, 2, RHD_R500},
{ 0x1002, 0x714B, 2, RHD_R500},
{ 0x1002, 0x714C, 2, RHD_R500},
{ 0x1002, 0x714D, 2, RHD_R500},
{ 0x1002, 0x714E, 2, RHD_R500},
{ 0x1002, 0x714F, 2, RHD_R500},
{ 0x1002, 0x7151, 2, RHD_R500},
{ 0x1002, 0x7152, 2, RHD_R500},
{ 0x1002, 0x7153, 2, RHD_R500},
{ 0x1002, 0x715E, 2, RHD_R500},
{ 0x1002, 0x715F, 2, RHD_R500},
{ 0x1002, 0x7180, 2, RHD_R500},
{ 0x1002, 0x7181, 2, RHD_R500},
{ 0x1002, 0x7183, 2, RHD_R500},
{ 0x1002, 0x7186, 2, RHD_R500},
{ 0x1002, 0x7187, 2, RHD_R500},
{ 0x1002, 0x7188, 2, RHD_R500},
{ 0x1002, 0x718A, 2, RHD_R500},
{ 0x1002, 0x718B, 2, RHD_R500},
{ 0x1002, 0x718C, 2, RHD_R500},
{ 0x1002, 0x718D, 2, RHD_R500},
{ 0x1002, 0x718F, 2, RHD_R500},
{ 0x1002, 0x7193, 2, RHD_R500},
{ 0x1002, 0x7196, 2, RHD_R500},
{ 0x1002, 0x719B, 2, RHD_R500},
{ 0x1002, 0x719F, 2, RHD_R500},
{ 0x1002, 0x71C0, 2, RHD_R500},
{ 0x1002, 0x71C1, 2, RHD_R500},
{ 0x1002, 0x71C2, 2, RHD_R500},
{ 0x1002, 0x71C3, 2, RHD_R500},
{ 0x1002, 0x71C4, 2, RHD_R500},
{ 0x1002, 0x71C5, 2, RHD_R500},
{ 0x1002, 0x71C6, 2, RHD_R500},
{ 0x1002, 0x71C7, 2, RHD_R500},
{ 0x1002, 0x71CD, 2, RHD_R500},
{ 0x1002, 0x71CE, 2, RHD_R500},
{ 0x1002, 0x71D2, 2, RHD_R500},
{ 0x1002, 0x71D4, 2, RHD_R500},
{ 0x1002, 0x71D5, 2, RHD_R500},
{ 0x1002, 0x71D6, 2, RHD_R500},
{ 0x1002, 0x71DA, 2, RHD_R500},
{ 0x1002, 0x71DE, 2, RHD_R500},
{ 0x1002, 0x7200, 2, RHD_R500},
{ 0x1002, 0x7210, 2, RHD_R500},
{ 0x1002, 0x7211, 2, RHD_R500},
{ 0x1002, 0x7240, 2, RHD_R500},
{ 0x1002, 0x7243, 2, RHD_R500},
{ 0x1002, 0x7244, 2, RHD_R500},
{ 0x1002, 0x7245, 2, RHD_R500},
{ 0x1002, 0x7246, 2, RHD_R500},
{ 0x1002, 0x7247, 2, RHD_R500},
{ 0x1002, 0x7248, 2, RHD_R500},
{ 0x1002, 0x7249, 2, RHD_R500},
{ 0x1002, 0x724A, 2, RHD_R500},
{ 0x1002, 0x724B, 2, RHD_R500},
{ 0x1002, 0x724C, 2, RHD_R500},
{ 0x1002, 0x724D, 2, RHD_R500},
{ 0x1002, 0x724E, 2, RHD_R500},
{ 0x1002, 0x724F, 2, RHD_R500},
{ 0x1002, 0x7280, 2, RHD_R500},
{ 0x1002, 0x7281, 2, RHD_R500},
{ 0x1002, 0x7283, 2, RHD_R500},
{ 0x1002, 0x7284, 2, RHD_R500},
{ 0x1002, 0x7287, 2, RHD_R500},
{ 0x1002, 0x7288, 2, RHD_R500},
{ 0x1002, 0x7289, 2, RHD_R500},
{ 0x1002, 0x728B, 2, RHD_R500},
{ 0x1002, 0x728C, 2, RHD_R500},
{ 0x1002, 0x7290, 2, RHD_R500},
{ 0x1002, 0x7291, 2, RHD_R500},
{ 0x1002, 0x7293, 2, RHD_R500},
{ 0x1002, 0x7297, 2, RHD_R500},
{ 0x1002, 0x791E, 2, RHD_RS690},
{ 0x1002, 0x791F, 2, RHD_RS690},
{ 0x1002, 0x796C, 2, RHD_R500},
{ 0x1002, 0x796D, 2, RHD_R500},
{ 0x1002, 0x796E, 2, RHD_R500},
{ 0x1002, 0x796F, 2, RHD_R500},
{ 0x1002, 0x9400, 2, RHD_R600},
{ 0x1002, 0x9401, 2, RHD_R600},
{ 0x1002, 0x9402, 2, RHD_R600},
{ 0x1002, 0x9403, 2, RHD_R600},
{ 0x1002, 0x94C0, 2, RHD_R600},
{ 0x1002, 0x94C1, 2, RHD_R600},
{ 0x1002, 0x94C3, 2, RHD_R600},
{ 0x1002, 0x94C4, 2, RHD_R600},
{ 0x1002, 0x94C6, 2, RHD_R600},
{ 0x1002, 0x94C7, 2, RHD_R600},
{ 0x1002, 0x94C8, 2, RHD_R600},
{ 0x1002, 0x94C9, 2, RHD_R600},
{ 0x1002, 0x94CB, 2, RHD_R600},
{ 0x1002, 0x9580, 2, RHD_R600},
{ 0x1002, 0x9581, 2, RHD_R600},
{ 0x1002, 0x9583, 2, RHD_R600},
{ 0x1002, 0x9586, 2, RHD_R600},
{ 0x1002, 0x9587, 2, RHD_R600},
{ 0x1002, 0x9588, 2, RHD_R600},
{ 0x1002, 0x9589, 2, RHD_R600},
{ 0x1002, 0x958A, 2, RHD_R600},
{ 0x1002, 0x958B, 2, RHD_R600},
{ 0, 0, 0, 0 }
};
/*
*
*/
static struct pci_dev *
DeviceLocate(struct pci_dev *devices, int bus, int dev, int func)
{
struct pci_dev *device;
for (device = devices; device; device = device->next)
if ((device->bus == bus) && (device->dev == dev) &&
(device->func == func))
return device;
return NULL;
}
/*
*
*/
static struct RHDDevice *
DeviceMatch(struct pci_dev *device)
{
int i;
for (i = 0; rhdDevices[i].vendor; i++)
if ((rhdDevices[i].vendor == device->vendor_id) &&
(rhdDevices[i].device == device->device_id))
return (rhdDevices + i);
return NULL;
}
/*
*
*/
static void *
MapBar(struct pci_dev *device, int ioBar, int devMem)
{
void *map;
if (!device->base_addr[ioBar] || !device->size[ioBar])
return NULL;
map = mmap(0, device->size[ioBar], PROT_WRITE | PROT_READ, MAP_SHARED,
devMem, device->base_addr[ioBar]);
/* printf("Mapped IO at 0x%08llX (BAR %1d: 0x%08llX)\n",
device->base_addr[io_bar], io_bar, device->size[io_bar]); */
return map;
}
/*
*
*/
CARD32
RegRead(void *map, int offset)
{
return *(volatile CARD32 *)((CARD8 *) map + offset);
}
/*
*
*/
void
RegWrite(void *map, int offset, CARD32 value)
{
*(volatile CARD32 *)((CARD8 *) map + offset) = value;
}
/*
*
*/
void
RegMask(void *map, int offset, CARD32 value, CARD32 mask)
{
CARD32 tmp;
tmp = RegRead(map, offset);
tmp &= ~mask;
tmp |= (value & mask);
RegWrite(map, offset, tmp);
}
/*
*
*/
static void
HPDReport(void *map)
{
int HPD = RegRead(map, DC_GPIO_HPD_Y);
printf(" HotPlug:");
if (!(HPD & 0x0101) && !((ChipType == RHD_R600) && (HPD & 0x00010000)))
printf(" RHD_HPD_NONE ");
else {
if (HPD & 0x1)
printf(" RHD_HPD_0");
if (HPD & 0x100)
printf(" RHD_HPD_1");
if ((ChipType == RHD_R600) && (HPD & 0x00010000))
printf(" RHD_HPD_2");
}
printf("\n");
}
/*
*
*/
static Bool
DACALoadDetect(void *map)
{
CARD32 CompEnable, Control1, Control2, DetectControl, Enable;
CARD8 ret;
CompEnable = RegRead(map, DACA_COMPARATOR_ENABLE);
Control1 = RegRead(map, DACA_CONTROL1);
Control2 = RegRead(map, DACA_CONTROL2);
DetectControl = RegRead(map, DACA_AUTODETECT_CONTROL);
Enable = RegRead(map, DACA_ENABLE);
RegWrite(map, DACA_ENABLE, 1);
RegMask(map, DACA_AUTODETECT_CONTROL, 0, 0x3);
RegMask(map, DACA_CONTROL2, 0, 0x1);
RegMask(map, DACA_CONTROL2, 0, 0x100);
RegWrite(map, DACA_FORCE_DATA, 0);
RegMask(map, DACA_CONTROL2, 0x1, 0x1);
RegMask(map, DACA_COMPARATOR_ENABLE, 0x00070000, 0x00070000);
RegWrite(map, DACA_CONTROL1, 0x00050802);
RegMask(map, DACA_POWERDOWN, 0, 0x1); /* Shut down Bandgap Voltage Reference Power */
usleep(5);
RegMask(map, DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */
RegWrite(map, DACA_FORCE_DATA, 0x1e6); /* 486 out of 1024 */
usleep(200);
RegMask(map, DACA_POWERDOWN, 0x01010100, 0x01010100); /* Enable RGB */
usleep(88);
RegMask(map, DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */
RegMask(map, DACA_COMPARATOR_ENABLE, 0x100, 0x100);
usleep(100);
/* Get RGB detect values
* If only G is detected, we could have a monochrome monitor,
* but we don't bother with this at the moment.
*/
ret = (RegRead(map, DACA_COMPARATOR_OUTPUT) & 0x0E) >> 1;
RegMask(map, DACA_COMPARATOR_ENABLE, CompEnable, 0x00FFFFFF);
RegWrite(map, DACA_CONTROL1, Control1);
RegMask(map, DACA_CONTROL2, Control2, 0x1FF);
RegMask(map, DACA_AUTODETECT_CONTROL, DetectControl, 0xFF);
RegMask(map, DACA_ENABLE, Enable, 0xFF);
return (ret & 0x07);
}
/*
*
*/
static Bool
DACBLoadDetect(void *map)
{
CARD32 CompEnable, Control1, Control2, DetectControl, Enable;
CARD8 ret;
CompEnable = RegRead(map, DACB_COMPARATOR_ENABLE);
Control1 = RegRead(map, DACB_CONTROL1);
Control2 = RegRead(map, DACB_CONTROL2);
DetectControl = RegRead(map, DACB_AUTODETECT_CONTROL);
Enable = RegRead(map, DACB_ENABLE);
RegWrite(map, DACB_ENABLE, 1);
RegMask(map, DACB_AUTODETECT_CONTROL, 0, 0x3);
RegMask(map, DACB_CONTROL2, 0, 0x1);
RegMask(map, DACB_CONTROL2, 0, 0x100);
RegWrite(map, DACB_FORCE_DATA, 0);
RegMask(map, DACB_CONTROL2, 0x1, 0x1);
RegMask(map, DACB_COMPARATOR_ENABLE, 0x00070000, 0x00070000);
RegWrite(map, DACB_CONTROL1, 0x50802);
RegMask(map, DACB_POWERDOWN, 0, 0x1); /* Shut down Bandgap Voltage Reference Power */
usleep(5);
RegMask(map, DACB_POWERDOWN, 0, 0x01010100); /* Shut down RGB */
RegWrite(map, DACB_FORCE_DATA, 0x1e6); /* 486 out of 1024 */
usleep(200);
RegMask(map, DACB_POWERDOWN, 0x01010100, 0x01010100); /* Enable RGB */
usleep(88);
RegMask(map, DACB_POWERDOWN, 0, 0x01010100); /* Shut down RGB */
RegMask(map, DACB_COMPARATOR_ENABLE, 0x100, 0x100);
usleep(100);
/*
* Get RGB detect values
* If only G is detected, we could have a monochrome monitor,
* but we don't bother with this at the moment.
*/
ret = (RegRead(map, DACB_COMPARATOR_OUTPUT) & 0x0E) >> 1;
RegMask(map, DACB_COMPARATOR_ENABLE, CompEnable, 0xFFFFFF);
RegWrite(map, DACB_CONTROL1, Control1);
RegMask(map, DACB_CONTROL2, Control2, 0x1FF);
RegMask(map, DACB_AUTODETECT_CONTROL, DetectControl, 0xFF);
RegMask(map, DACB_ENABLE, Enable, 0xFF);
return (ret & 0x07);
}
/*
*
*/
static Bool
TMDSALoadDetect(void *map)
{
CARD32 Enable, Control, Detect;
Bool ret;
Enable = RegRead(map, TMDSA_TRANSMITTER_ENABLE);
Control = RegRead(map, TMDSA_TRANSMITTER_CONTROL);
Detect = RegRead(map, TMDSA_LOAD_DETECT);
/* r500 needs a tiny bit more work :) */
if (ChipType < RHD_R600) {
RegMask(map, TMDSA_TRANSMITTER_ENABLE, 0x3, 0x3);
RegMask(map, TMDSA_TRANSMITTER_CONTROL, 0x1, 0x3);
}
RegMask(map, TMDSA_LOAD_DETECT, 0x1, 0x1);
usleep(1);
ret = RegRead(map, TMDSA_LOAD_DETECT) & 0x10;
RegMask(map, TMDSA_LOAD_DETECT, Detect, 0x1);
if (ChipType < RHD_R600) {
RegWrite(map, TMDSA_TRANSMITTER_ENABLE, Enable);
RegWrite(map, TMDSA_TRANSMITTER_CONTROL, Control);
}
return ret;
}
/*
*
*/
static void
LoadReport(void *map)
{
Bool DACA, DACB, TMDSA;
DACA = DACALoadDetect(map);
DACB = DACBLoadDetect(map);
TMDSA =TMDSALoadDetect(map);
printf(" Load Detection:");
if (!DACA && !DACB && !TMDSA)
printf(" RHD_OUTPUT_NONE ");
else {
if (DACA)
printf(" RHD_OUTPUT_DACA");
if (DACB)
printf(" RHD_OUTPUT_DACB");
if (TMDSA)
printf(" RHD_OUTPUT_TMDSA");
}
printf("\n");
}
/*
*
*/
CARD32
getDDCSpeed(void)
{
CARD32 clock, ret;
switch (AtomData.FirmwareInfoVersion.crev) {
case 1:
clock = AtomData.FirmwareInfo.FirmwareInfo->ulDefaultEngineClock;
break;
case 2:
clock = AtomData.FirmwareInfo.FirmwareInfo_V_1_2->ulDefaultEngineClock;
break;
case 3:
clock = AtomData.FirmwareInfo.FirmwareInfo_V_1_3->ulDefaultEngineClock;
break;
case 4:
clock = AtomData.FirmwareInfo.FirmwareInfo_V_1_4->ulDefaultEngineClock;
break;
default:
/* no AtomBIOS info; use save default */
clock = 70000;
}
clock *= 10;
switch (ChipType) {
case RHD_R500:
case RHD_RS690:
ret = (0x7F << 8)
+ (clock) / (4 * 0x7F * TARGET_HW_I2C_CLOCK);
break;
case RHD_R600:
ret = (clock) / TARGET_HW_I2C_CLOCK;
break;
default:
ret = 0;
}
#ifdef DEBUG
printf("%s: Clock: %i Prescale: 0x%x\n",__func__,clock,ret);
#endif
return ret;
}
/*
* R600 DDC defines.
*/
enum _r6xxI2CBits {
/* R6_DC_I2C_TRANSACTION0 */
R6_DC_I2C_RW0 = (0x1 << 0),
R6_DC_I2C_STOP_ON_NACK0 = (0x1 << 8),
R6_DC_I2C_ACK_ON_READ0 = (0x1 << 9),
R6_DC_I2C_START0 = (0x1 << 12),
R6_DC_I2C_STOP0 = (0x1 << 13),
R6_DC_I2C_COUNT0 = (0xff << 16),
/* R6_DC_I2C_TRANSACTION1 */
R6_DC_I2C_RW1 = (0x1 << 0),
R6_DC_I2C_STOP_ON_NACK1 = (0x1 << 8),
R6_DC_I2C_ACK_ON_READ1 = (0x1 << 9),
R6_DC_I2C_START1 = (0x1 << 12),
R6_DC_I2C_STOP1 = (0x1 << 13),
R6_DC_I2C_COUNT1 = (0xff << 16),
/* R6_DC_I2C_DATA */
R6_DC_I2C_DATA_RW = (0x1 << 0),
R6_DC_I2C_DATA_BIT = (0xff << 8),
R6_DC_I2C_INDEX = (0xff << 16),
R6_DC_I2C_INDEX_WRITE = (0x1 << 31),
/* R6_DC_I2C_CONTROL */
R6_DC_I2C_GO = (0x1 << 0),
R6_DC_I2C_SOFT_RESET = (0x1 << 1),
R6_DC_I2C_SEND_RESET = (0x1 << 2),
R6_DC_I2C_SW_STATUS_RESET = (0x1 << 3),
R6_DC_I2C_SDVO_EN = (0x1 << 4),
R6_DC_I2C_SDVO_ADDR_SEL = (0x1 << 6),
R6_DC_I2C_DDC_SELECT = (0x7 << 8),
R6_DC_I2C_TRANSACTION_COUNT = (0x3 << 20),
R6_DC_I2C_SW_DONE_INT = (0x1 << 0),
R6_DC_I2C_SW_DONE_ACK = (0x1 << 1),
R6_DC_I2C_SW_DONE_MASK = (0x1 << 2),
R6_DC_I2C_DDC1_HW_DONE_INT = (0x1 << 4),
R6_DC_I2C_DDC1_HW_DONE_ACK = (0x1 << 5),
R6_DC_I2C_DDC1_HW_DONE_MASK = (0x1 << 6),
R6_DC_I2C_DDC2_HW_DONE_INT = (0x1 << 8),
R6_DC_I2C_DDC2_HW_DONE_ACK = (0x1 << 9),
R6_DC_I2C_DDC2_HW_DONE_MASK = (0x1 << 10),
R6_DC_I2C_DDC3_HW_DONE_INT = (0x1 << 12),
R6_DC_I2C_DDC3_HW_DONE_ACK = (0x1 << 13),
R6_DC_I2C_DDC3_HW_DONE_MASK = (0x1 << 14),
R6_DC_I2C_DDC4_HW_DONE_INT = (0x1 << 16),
R6_DC_I2C_DDC4_HW_DONE_ACK = (0x1 << 17),
R6_DC_I2C_DDC4_HW_DONE_MASK = (0x1 << 18),
/* R6_DC_I2C_SW_STATUS */
R6_DC_I2C_SW_STATUS_BIT = (0x3 << 0),
R6_DC_I2C_SW_DONE = (0x1 << 2),
R6_DC_I2C_SW_ABORTED = (0x1 << 4),
R6_DC_I2C_SW_TIMEOUT = (0x1 << 5),
R6_DC_I2C_SW_INTERRUPTED = (0x1 << 6),
R6_DC_I2C_SW_BUFFER_OVERFLOW = (0x1 << 7),
R6_DC_I2C_SW_STOPPED_ON_NACK = (0x1 << 8),
R6_DC_I2C_SW_SDVO_NACK = (0x1 << 10),
R6_DC_I2C_SW_NACK0 = (0x1 << 12),
R6_DC_I2C_SW_NACK1 = (0x1 << 13),
R6_DC_I2C_SW_NACK2 = (0x1 << 14),
R6_DC_I2C_SW_NACK3 = (0x1 << 15),
R6_DC_I2C_SW_REQ = (0x1 << 18)
};
/*
*
*/
static Bool
R6xxI2CSetupStatus(void *map, int channel)
{
channel &= 0xf;
CARD16 i2c_speed;
i2c_speed = getDDCSpeed();
if (!i2c_speed)
return FALSE;
switch (channel) {
case 0:
RegMask(map, DC_GPIO_DDC1_MASK, 0x0, 0xffff);
RegMask(map, DC_GPIO_DDC1_A, 0x0, 0xffff);
RegMask(map, DC_GPIO_DDC1_EN, 0x0, 0xffff);
RegMask(map, R6_DC_I2C_DDC1_SPEED, (i2c_speed << 16) | 2,
0xFFFF00FF);
RegWrite(map, R6_DC_I2C_DDC1_SETUP, 0x30000000);
break;
case 1:
RegMask(map, DC_GPIO_DDC2_MASK, 0x0, 0xffff);
RegMask(map, DC_GPIO_DDC2_A, 0x0, 0xffff);
RegMask(map, DC_GPIO_DDC2_EN, 0x0, 0xffff);
RegMask(map, R6_DC_I2C_DDC2_SPEED, (i2c_speed << 16) | 2,
0xffff00ff);
RegWrite(map, R6_DC_I2C_DDC2_SETUP, 0x30000000);
break;
case 2:
RegMask(map, DC_GPIO_DDC3_MASK, 0x0, 0xffff);
RegMask(map, DC_GPIO_DDC3_A, 0x0, 0xffff);
RegMask(map, DC_GPIO_DDC3_EN, 0x0, 0xffff);
RegMask(map, R6_DC_I2C_DDC3_SPEED, (i2c_speed << 16) | 2,
0xffff00ff);
RegWrite(map, R6_DC_I2C_DDC3_SETUP, 0x30000000);
break;
case 3:
RegMask(map, DC_GPIO_DDC4_MASK, 0x0, 0xffff);
RegMask(map, DC_GPIO_DDC4_A, 0x0, 0xffff);
RegMask(map, DC_GPIO_DDC4_EN, 0x0, 0xffff);
RegMask(map, R6_DC_I2C_DDC4_SPEED, (i2c_speed << 16) | 2,
0xffff00ff);
RegWrite(map, R6_DC_I2C_DDC4_SETUP, 0x30000000);
break;
default:
return FALSE;
}
RegWrite(map, R6_DC_I2C_CONTROL, channel << 8);
RegMask(map, R6_DC_I2C_INTERRUPT_CONTROL, 0x2, 0x2);
RegMask(map, R6_DC_I2C_ARBITRATION, 0, 0xff);
return TRUE;
}
/*
*
*/
static Bool
R6xxI2CStatus(void *map)
{
int count = 800;
CARD32 val;
while (--count) {
usleep(1000);
val = RegRead(map, R6_DC_I2C_SW_STATUS);
if (val & R6_DC_I2C_SW_DONE)
break;
}
RegMask(map, R6_DC_I2C_INTERRUPT_CONTROL, R6_DC_I2C_SW_DONE_ACK,
R6_DC_I2C_SW_DONE_ACK);
#ifdef DEBUG
fprintf(stderr, "I2CStatus: %x\n",val);
#endif
if (!count || (val & (R6_DC_I2C_SW_STOPPED_ON_NACK
| R6_DC_I2C_SW_NACK0 | R6_DC_I2C_SW_NACK1 | 0x3)))
return FALSE; /* 2 */
return TRUE; /* 1 */
}
/*
*
*/
static Bool
R6xxDDCProbe(void *map, int Channel, unsigned char slave)
{
Bool ret = FALSE;
CARD32 data;
if (!R6xxI2CSetupStatus(map, Channel))
return FALSE;
RegMask(map, R6_DC_I2C_CONTROL, 0, 0x00300000); /* 1 Transaction */
RegMask(map, R6_DC_I2C_TRANSACTION0, /* only slave */
R6_DC_I2C_STOP_ON_NACK0 | R6_DC_I2C_START0
| R6_DC_I2C_STOP0 | (0 << 16), 0x00ffffff);
data = R6_DC_I2C_INDEX_WRITE | ( slave << 8 ) | (0 << 16);
RegWrite(map, R6_DC_I2C_DATA, data);
RegMask(map, R6_DC_I2C_CONTROL, R6_DC_I2C_GO, R6_DC_I2C_GO);
ret = R6xxI2CStatus(map);
RegMask(map, R6_DC_I2C_CONTROL, 0x2, 0xff);
usleep(1000);
RegWrite(map, R6_DC_I2C_CONTROL, 0);
return ret;
}
enum _rhdRS69I2CBits {
/* RS69_DC_I2C_TRANSACTION0 */
RS69_DC_I2C_RW0 = (0x1 << 0),
RS69_DC_I2C_STOP_ON_NACK0 = (0x1 << 8),
RS69_DC_I2C_START0 = (0x1 << 12),
RS69_DC_I2C_STOP0 = (0x1 << 13),
/* RS69_DC_I2C_TRANSACTION1 */
RS69_DC_I2C_RW1 = (0x1 << 0),
RS69_DC_I2C_START1 = (0x1 << 12),
RS69_DC_I2C_STOP1 = (0x1 << 13),
/* RS69_DC_I2C_DATA */
RS69_DC_I2C_DATA_RW = (0x1 << 0),
RS69_DC_I2C_INDEX_WRITE = (0x1 << 31),
/* RS69_DC_I2C_CONTROL */
RS69_DC_I2C_GO = (0x1 << 0),
RS69_DC_I2C_TRANSACTION_COUNT = (0x3 << 20),
RS69_DC_I2C_SW_DONE_ACK = (0x1 << 1),
/* RS69_DC_I2C_SW_STATUS */
RS69_DC_I2C_SW_DONE = (0x1 << 2),
RS69_DC_I2C_SW_STOPPED_ON_NACK = (0x1 << 8),
RS69_DC_I2C_SW_NACK0 = (0x1 << 12),
RS69_DC_I2C_SW_NACK1 = (0x1 << 13)
};
/*
*
*/
static Bool
RS69I2CStatus(void *map)
{
int count = 800;
volatile CARD32 val;
while (--count) {
usleep(10);
val = RegRead(map, RS69_DC_I2C_SW_STATUS);
#ifdef DEBUG
fprintf(stderr,"I2CStatus : 0x%x %i\n",(unsigned int)val,count);
#endif
if (val & RS69_DC_I2C_SW_DONE)
break;
}
RegMask(map, RS69_DC_I2C_INTERRUPT_CONTROL, RS69_DC_I2C_SW_DONE_ACK,
RS69_DC_I2C_SW_DONE_ACK);
if (!count || (val & (RS69_DC_I2C_SW_STOPPED_ON_NACK
| RS69_DC_I2C_SW_NACK0 | RS69_DC_I2C_SW_NACK1
| 0x3)))
return FALSE; /* 2 */
return TRUE; /* 1 */
}
/*
*
*/
static Bool
RS69I2CSetupStatus(void *map, int line)
{
CARD32 ddc;
CARD16 prescale;
prescale = getDDCSpeed();
if (!prescale)
return FALSE;
RegMask(map, 0x28, 0x200, 0x200);
RegMask(map, RS69_DC_I2C_UNKNOWN_1, prescale << 16 | 0x2, 0xffff00ff);
/* add SDVO handling later */
switch (AtomData.GPIO_I2C_Info->asGPIO_Info[line & 0xf]
.usClkMaskRegisterIndex) {
case 0x1f90:
ddc = 0; /* ddc1 */
break;
case 0x1f94: /* ddc2 */
ddc = 1;
break;
default:
ddc = 2; /* ddc3 */
break;
}
#ifdef DEBUG
printf("DDC: line: %i -> %i port: %x\n",line,ddc,
AtomData.GPIO_I2C_Info->asGPIO_Info[line & 0xf]
.usClkMaskRegisterIndex);
#endif
RegMask(map, RS69_DC_I2C_CONTROL, ddc << 8, 0xff << 8);
RegWrite(map, RS69_DC_I2C_DDC_SETUP_Q, 0x30000000);
RegMask(map, RS69_DC_I2C_CONTROL, (line & 0x3) << 16, 0xff << 16);
RegMask(map, RS69_DC_I2C_INTERRUPT_CONTROL, 0x2, 0x2);
RegMask(map, RS69_DC_I2C_UNKNOWN_2, 0x2, 0xff);
return TRUE;
}
/*
*
*/
static Bool
RS69DDCProbe(void *map, int Channel, unsigned char slave)
{
Bool ret = FALSE;
CARD32 data;
if (!RS69I2CSetupStatus(map, Channel))
return FALSE;
RegMask(map, RS69_DC_I2C_CONTROL, 0, RS69_DC_I2C_TRANSACTION_COUNT); /* 1 Transaction */
RegMask(map, RS69_DC_I2C_TRANSACTION0, /* only slave */
RS69_DC_I2C_STOP_ON_NACK0 | RS69_DC_I2C_START0
| RS69_DC_I2C_STOP0 | (0 << 16), 0x00ffffff);
data = RS69_DC_I2C_INDEX_WRITE | ( slave << 8 ) | (0 << 16);
RegWrite(map, RS69_DC_I2C_DATA, data);
RegMask(map, RS69_DC_I2C_CONTROL, RS69_DC_I2C_GO, RS69_DC_I2C_GO);
ret = RS69I2CStatus(map);
RegMask(map, RS69_DC_I2C_CONTROL, 0x2, 0xff);
usleep(1000);
RegWrite(map, RS69_DC_I2C_CONTROL, 0);
return ret;
}
enum _rhdR5xxI2CBits {
/* R5_DC_I2C_STATUS1 */
R5_DC_I2C_DONE = (0x1 << 0),
R5_DC_I2C_NACK = (0x1 << 1),
R5_DC_I2C_HALT = (0x1 << 2),
R5_DC_I2C_GO = (0x1 << 3),
/* R5_DC_I2C_RESET */
R5_DC_I2C_SOFT_RESET = (0x1 << 0),
R5_DC_I2C_ABORT = (0x1 << 8),
/* R5_DC_I2C_CONTROL1 */
R5_DC_I2C_START = (0x1 << 0),
R5_DC_I2C_STOP = (0x1 << 1),
R5_DC_I2C_RECEIVE = (0x1 << 2),
R5_DC_I2C_EN = (0x1 << 8),
R5_DC_I2C_PIN_SELECT = (0x3 << 16),
/* R5_DC_I2C_CONTROL2 */
R5_DC_I2C_ADDR_COUNT = (0x7 << 0),
R5_DC_I2C_DATA_COUNT = (0xf << 8),
R5_DC_I2C_PRESCALE_LOWER = (0xff << 16),
R5_DC_I2C_PRESCALE_UPPER = (0xff << 24),
/* R5_DC_I2C_CONTROL3 */
R5_DC_I2C_DATA_DRIVE_EN = (0x1 << 0),
R5_DC_I2C_DATA_DRIVE_SEL = (0x1 << 1),
R5_DC_I2C_CLK_DRIVE_EN = (0x1 << 7),
R5_DC_I2C_RD_INTRA_BYTE_DELAY = (0xff << 8),
R5_DC_I2C_WR_INTRA_BYTE_DELAY = (0xff << 16),
R5_DC_I2C_TIME_LIMIT = (0xff << 24),
/* R5_DC_I2C_DATA */
R5_DC_I2C_DATA_BIT = (0xff << 0),
/* R5_DC_I2C_INTERRUPT_CONTROL */
R5_DC_I2C_INTERRUPT_STATUS = (0x1 << 0),
R5_DC_I2C_INTERRUPT_AK = (0x1 << 8),
R5_DC_I2C_INTERRUPT_ENABLE = (0x1 << 16),
/* R5_DC_I2C_ARBITRATION */
R5_DC_I2C_SW_WANTS_TO_USE_I2C = (0x1 << 0),
R5_DC_I2C_SW_CAN_USE_I2C = (0x1 << 1),
R5_DC_I2C_SW_DONE_USING_I2C = (0x1 << 8),
R5_DC_I2C_HW_NEEDS_I2C = (0x1 << 9),
R5_DC_I2C_ABORT_HDCP_I2C = (0x1 << 16),
R5_DC_I2C_HW_USING_I2C = (0x1 << 17)
};
/*
*
*/
static Bool
R5xxI2CStatus(void *map)
{
int count = 800;
CARD32 res;
while (count-- != 0) {
usleep (1000);
if (((RegRead(map, R5_DC_I2C_STATUS1))
& R5_DC_I2C_GO) != 0)
continue;
res = RegRead(map, R5_DC_I2C_STATUS1);
#ifdef DEBUG
fprintf(stderr, "I2CStatus: %x\n",res);
#endif
if (res & R5_DC_I2C_DONE)
return TRUE;
else
return FALSE;
}
RegMask(map, R5_DC_I2C_RESET, R5_DC_I2C_ABORT, 0xff00);
return FALSE;
}
/*
*
*/
static Bool
R5xxDDCProbe(void *map, int Channel, unsigned char slave)
{
Bool ret = FALSE;
CARD32 SaveControl1, save_494;
CARD16 prescale;
prescale = getDDCSpeed();
if (!prescale)
return FALSE;
RegMask(map, 0x28, 0x200, 0x200);
SaveControl1 = RegRead(map, R5_DC_I2C_CONTROL1);
save_494 = RegRead(map, 0x494);
RegMask(map, 0x494, 1, 1);
RegMask(map, R5_DC_I2C_ARBITRATION, R5_DC_I2C_SW_WANTS_TO_USE_I2C,
R5_DC_I2C_SW_WANTS_TO_USE_I2C);
RegMask(map, R5_DC_I2C_STATUS1, R5_DC_I2C_DONE
| R5_DC_I2C_NACK
| R5_DC_I2C_HALT, 0xff);
RegMask(map, R5_DC_I2C_RESET, R5_DC_I2C_SOFT_RESET, 0xffff);
RegWrite(map, R5_DC_I2C_RESET, 0);
RegMask(map, R5_DC_I2C_CONTROL1,
(Channel & 0x0f) << 16 | R5_DC_I2C_EN,
R5_DC_I2C_PIN_SELECT | R5_DC_I2C_EN);
/* addr_count = 1; data_count = 1 */
RegWrite(map, R5_DC_I2C_CONTROL2, prescale << 16 | 0x101);
/* time limit 30 */
RegMask(map, R5_DC_I2C_CONTROL3, 0x30 << 24, 0xff << 24);
RegWrite(map, R5_DC_I2C_DATA, slave); /* slave */
RegWrite(map, R5_DC_I2C_DATA, 0);
RegMask(map, R5_DC_I2C_CONTROL1,
R5_DC_I2C_START | R5_DC_I2C_STOP, 0xff);
RegMask(map, R5_DC_I2C_STATUS1, R5_DC_I2C_GO, 0xff);
ret = R5xxI2CStatus(map);
RegMask(map, R5_DC_I2C_STATUS1,
R5_DC_I2C_DONE
| R5_DC_I2C_NACK
| R5_DC_I2C_HALT, 0xff);
RegMask(map, R5_DC_I2C_RESET, R5_DC_I2C_SOFT_RESET, 0xff);
RegWrite(map,R5_DC_I2C_RESET, 0);
RegMask(map, R5_DC_I2C_ARBITRATION,
R5_DC_I2C_SW_DONE_USING_I2C, 0xff00);
RegWrite(map, R5_DC_I2C_CONTROL1, SaveControl1);
RegWrite(map, 0x494, save_494);
RegMask(map, 0x28, 0, 0x200);
return ret;
}
/*
*
*/
static Bool
DDCProbe(void *map, int Channel, unsigned char slave)
{
switch (ChipType) {
case RHD_R500:
return R5xxDDCProbe(map, Channel, slave);
case RHD_RS690:
return RS69DDCProbe(map, Channel, slave);
case RHD_R600:
return R6xxDDCProbe(map, Channel, slave);
default:
return FALSE;
}
}
/*
*
*/
#define EDID_SLAVE 0xA0
static void
DDCReport(void *map)
{
Bool Chan0, Chan1, Chan2, Chan3;
Chan0 = DDCProbe(map, 0, EDID_SLAVE);
Chan1 = DDCProbe(map, 1, EDID_SLAVE);
Chan2 = DDCProbe(map, 2, EDID_SLAVE);
if (ChipType >= RHD_R600)
Chan3 = DDCProbe(map, 3, EDID_SLAVE);
else
Chan3 = FALSE;
printf(" DDC:");
if (!Chan0 && !Chan1 && !Chan2 && !Chan3)
printf(" RHD_DDC_NONE ");
else {
if (Chan0)
printf(" RHD_DDC_0");
if (Chan1)
printf(" RHD_DDC_1");
if (Chan2)
printf(" RHD_DDC_2");
if (Chan3)
printf(" RHD_DDC_3");
}
printf("\n");
}
/*
*
*/
static void
DDCScanBus(void *map)
{
int channel;
unsigned char slave;
int max_chan = ((ChipType >= RHD_R600) ? 3 : 2);
for (channel = 0; channel < max_chan; channel ++) {
int state = 0;
for (slave = 0x8; slave < 0x78; slave++ ) {
if (DDCProbe(map, channel, slave << 1)) {
if (state == 0) {
printf(" DDC Line[%i]: Slaves: ", channel);
state = 1;
}
printf("%x ", slave << 1);
}
}
if (state == 1)
printf("\n");
}
}
/*
*
*/
static void
LVDSReport(void *map)
{
Bool Bits24 = FALSE, DualLink = FALSE, Fpdi = FALSE;
if (ChipType == RHD_R600) {
/* printf("No information for LVTMA on R600 has been made available yet.\n"); */
return;
}
if (!(RegRead(map, LVTMA_CNTL) & 0x1) ||
(RegRead(map, LVTMA_MODE) & 0x1))
return;
printf(" LVDS Info:\n");
DualLink = RegRead(map, LVTMA_CNTL) & 0x01000000;
Bits24 = RegRead(map, LVTMA_LVDS_DATA_CNTL) & 0x1;
Fpdi = RegRead(map, LVTMA_LVDS_DATA_CNTL) & 0x1;
printf("\t%dbits, %s link, %s Panel found.\n",
Bits24 ? 24 : 18,
DualLink ? "dual" : "single",
Fpdi ? "FPDI" : "LDI");
printf("\tPower Timing: 0x%03X, 0x%03X, 0x%02X, 0x%02X, 0x%03X\n",
RegRead(map, LVTMA_PWRSEQ_REF_DIV) & 0xFFF,
(RegRead(map, LVTMA_PWRSEQ_REF_DIV) >> 16) & 0xFFF,
((RegRead(map, LVTMA_PWRSEQ_DELAY1) & 0xFF) * 2 + 1) / 5,
(((RegRead(map, LVTMA_PWRSEQ_DELAY1) >> 8) & 0xFF) * 2 + 1)/ 5,
(RegRead(map, LVTMA_PWRSEQ_DELAY2) & 0xFFF) << 2);
printf("\tMacro: 0x%08X, Clock Pattern: 0x%04X\n",
RegRead(map, LVTMA_MACRO_CONTROL),
(RegRead(map, LVTMA_TRANSMITTER_CONTROL) >> 16) & 0x3FF);
}
/*
*
*/
Bool
WriteToFile(char *name, unsigned char *buffer, int size)
{
int fd = open(name, O_CREAT | O_TRUNC | O_WRONLY,S_IRUSR | S_IWUSR);
int ct = 0;
if (fd < 0) {
fprintf(stderr,"Cannot open file %s: %s\n",name,strerror(errno));
goto error;
} else {
while (1) {
int ret = write(fd, buffer + ct, size - ct);
if (ret < 0) {
if (errno == EAGAIN || errno == EINVAL)
continue;
else {
fprintf(stderr,"Cannot write output file: %s\n",
strerror(errno));
close (fd);
goto error;
}
} else {
ct += ret;
if (ct == size)
break;
}
}
close (fd);
return TRUE;
}
error:
return FALSE;
}
/*
*
*/
unsigned char *
GetVBIOS(int *size)
{
int i;
unsigned char *rombase;
char chksm = 0;
int saved_errno;
int fd;
if ((fd = open(DEV_MEM, O_RDONLY)) < 0) {
fprintf(stderr,"Cannot open " DEV_MEM " (%s),\n",strerror(errno));
return FALSE;
}
rombase = mmap((caddr_t)0, VBIOS_MAXSIZE, PROT_READ, MAP_SHARED, fd,
VBIOS_BASE);
saved_errno = errno;
close (fd);
if (rombase == MAP_FAILED) {
fprintf(stderr,"Cannot map (0x%08x:0x%x) (%s)\n",VBIOS_BASE,
VBIOS_MAXSIZE,
strerror(saved_errno));
return FALSE;
}
if (rombase[0] != 0x55 || rombase[1] != 0xaa) {
fprintf(stderr,"No BIOS Signature found!\n");
} else {
*size = rombase[2] * 512;
for (i = 0; i < *size; i++) {
chksm += rombase[i];
}
if (chksm)
fprintf(stderr,"Warning: VBIOS chksum incorrect!\n");
}
return rombase;
}
/*
*
*/
void
FreeVBIOS(unsigned char *rombase, int size)
{
munmap(rombase,size);
}
/*
*
*/
static int
AnalyzeCommonHdr(ATOM_COMMON_TABLE_HEADER *hdr)
{
if (hdr->usStructureSize == 0xaa55)
return FALSE;
return TRUE;
}
/*
*
*/
static int
AnalyzeRomHdr(unsigned char *rombase,
ATOM_ROM_HEADER *hdr,
int *data_offset)
{
if (AnalyzeCommonHdr(&hdr->sHeader) == -1) {
return FALSE;
}
*data_offset = hdr->usMasterDataTableOffset;
return TRUE;
}
/*
*
*/
static int
AnalyzeRomDataTable(unsigned char *base, int offset,
void *ptr,short *size)
{
ATOM_COMMON_TABLE_HEADER *table = (ATOM_COMMON_TABLE_HEADER *)
(base + offset);
if (!*size || AnalyzeCommonHdr(table) == -1) {
if (*size) *size -= 2;
*(void **)ptr = NULL;
return FALSE;
}
*size -= 2;
*(void **)ptr = (void *)(table);
return TRUE;
}
/*
*
*/
static Bool
GetAtomBiosTableRevisionAndSize(ATOM_COMMON_TABLE_HEADER *hdr,
CARD8 *contentRev,
CARD8 *formatRev,
short *size)
{
if (!hdr)
return FALSE;
if (contentRev) *contentRev = hdr->ucTableContentRevision;
if (formatRev) *formatRev = hdr->ucTableFormatRevision;
if (size) *size = (short)hdr->usStructureSize
- sizeof(ATOM_COMMON_TABLE_HEADER);
return TRUE;
}
static Bool
AnalyzeMasterDataTable(unsigned char *base,
ATOM_MASTER_DATA_TABLE *table)
{
ATOM_MASTER_LIST_OF_DATA_TABLES *data_table =
&table->ListOfDataTables;
short size;
if (!AnalyzeCommonHdr(&table->sHeader))
return FALSE;
if (!GetAtomBiosTableRevisionAndSize(&table->sHeader,NULL,NULL,&size))
return FALSE;
AnalyzeRomDataTable(base,data_table->FirmwareInfo,&(AtomData.FirmwareInfo.base),&size);
GetAtomBiosTableRevisionAndSize(AtomData.FirmwareInfo.base,
&AtomData.FirmwareInfoVersion.crev,
&AtomData.FirmwareInfoVersion.frev,
NULL);
AnalyzeRomDataTable(base,data_table->GPIO_I2C_Info,&(AtomData.GPIO_I2C_Info),&size);
GetAtomBiosTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)AtomData.GPIO_I2C_Info,
&AtomData.GPIO_I2C_InfoVersion.crev,
&AtomData.GPIO_I2C_InfoVersion.frev,
NULL);
return TRUE;
}
void
print_help(const char* progname, const char* message, const char* msgarg)
{
if (message != NULL)
fprintf(stderr, "%s %s\n", message, msgarg);
fprintf(stderr, "Usage: %s [options] PCI-tag\n"
" Options: -d: dumpBios\n"
" -s: scanDDCBus\n"
" PCI-tag: bus:dev.func\n\n",
progname);
}
/*
*
*/
static Bool
InterpretATOMBIOS(unsigned char *base)
{
int data_offset;
unsigned short atom_romhdr_off = *(unsigned short*)
(base + OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
ATOM_ROM_HEADER *atom_rom_hdr =
(ATOM_ROM_HEADER *)(base + atom_romhdr_off);
if (memcmp("ATOM",&atom_rom_hdr->uaFirmWareSignature,4)) {
fprintf(stderr,"No AtomBios signature found\n");
return FALSE;
}
if (!AnalyzeRomHdr(base, atom_rom_hdr, &data_offset)) {
fprintf(stderr, "RomHeader invalid\n");
return FALSE;
}
if (!AnalyzeMasterDataTable(base, (ATOM_MASTER_DATA_TABLE *)
(base + data_offset))) {
fprintf(stderr, "ROM Master Table invalid\n");
return FALSE;
}
return TRUE;
}
/*
*
*/
int
main(int argc, char *argv[])
{
struct pci_dev *device;
struct pci_access *pciAccess;
struct RHDDevice *rhdDevice;
int devMem;
void *io;
int bus, dev, func;
int ret;
int saved_errno;
Bool dumpBios, deviceSet, scanDDCBus;
int i;
unsigned char *rombase;
int size;
printf("%s: v%s, %s\n",
"rhd_conntest", PACKAGE_VERSION, GIT_MESSAGE);
/* init libpci */
pciAccess = pci_alloc();
pci_init(pciAccess);
pci_scan_bus(pciAccess);
if (argc < 2) {
print_help(argv[0], "Missing argument: please provide a PCI tag\n",
"");
return 1;
}
for (i = 1; i < argc; i++) {
if (!strncmp("-d",argv[i],3)) {
dumpBios = TRUE;
} else if (!strncmp("-s",argv[i],3)) {
scanDDCBus = TRUE;
} else if (!strncmp("-",argv[i],1)) {
print_help(argv[0], "Unknown option", argv[i]);
return 1;
} else {
ret = sscanf(argv[i], "%x:%x.%x", &bus, &dev, &func);
if (ret != 3) {
ret = sscanf(argv[i], "%x:%x:%x", &bus, &dev, &func);
if (ret != 3) {
ret = sscanf(argv[i], "%d:%d.%d", &bus, &dev, &func);
if (ret != 3)
ret = sscanf(argv[i], "%d:%d:%d", &bus, &dev, &func);
}
}
if (ret != 3) {
print_help(argv[0], "Unable to parse the PCI tag argument: ",
argv[i]);
return 1;
}
deviceSet = TRUE;
}
}
if (deviceSet) {
/* find our toy */
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;
}
rhdDevice = DeviceMatch(device);
if (!rhdDevice) {
fprintf(stderr,
"Unknown device: 0x%04X:0x%04X (%02X:%02X.%02X).\n",
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");
return 1;
}
if (!InterpretATOMBIOS(rombase)) {
fprintf(stderr, "Cannot analyze AtomBIOS\n");
return 1;
}
if (dumpBios) {
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));
}
WriteToFile(name, rombase, size);
}
if (!deviceSet)
return 0;
if (rhdDevice->bar > 5) {
fprintf(stderr, "Program error: No acceptable 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);
/* make sure we can actually read DEV_MEM before we do anything else */
devMem = open(DEV_MEM, O_RDWR);
if (devMem < 0) {
fprintf(stderr, "Unable to open "DEV_MEM": %s.\n", strerror(errno));
return errno;
}
io = MapBar(device, rhdDevice->bar, devMem);
saved_errno = errno;
close (devMem);
if (!io) {
fprintf(stderr, "Unable to map IO memory: %s.\n",
strerror(saved_errno));
return 1;
}
ChipType = rhdDevice->type;
LoadReport(io);
HPDReport(io);
DDCReport(io);
LVDSReport(io);
if (scanDDCBus)
DDCScanBus(io);
FreeVBIOS(rombase, size);
return 0;
}