/* * Copyright 2007, 2008 Luc Verhaegen * Copyright 2007, 2008 Matthias Hopf * Copyright 2007, 2008 Egbert Eich * Copyright 2007, 2008 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. * */ /* #define DEBUG */ #include #include #include #include #include #include #include #include #include #include #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; #if __BYTE_ORDER == __LITTLE_ENDIAN #define SHORT(x) (x) #else #define SHORT(x) (((x & 0xff) << 8) | ((x & 0xff) >> 8)) #endif #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, RV620_DACA_ENABLE = 0x7000, RV620_DACA_SOURCE_SELECT = 0x7004, RV620_DACA_AUTODETECT_CONTROL = 0x7028, RV620_DACA_AUTODETECT_STATUS = 0x7034, RV620_DACA_AUTODETECT_INT_CONTROL = 0x7038, RV620_DACA_FORCE_OUTPUT_CNTL = 0x703C, RV620_DACA_FORCE_DATA = 0x7040, RV620_DACA_POWERDOWN = 0x7050, /* RV620_DACB_CONTROL1 moved */ RV620_DACA_CONTROL2 = 0x7058, RV620_DACA_COMPARATOR_ENABLE = 0x705C, RV620_DACA_CONTROL1 = 0x7ef4, /* 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, RV620_DACB_ENABLE = 0x7100, RV620_DACB_SOURCE_SELECT = 0x7104, RV620_DACB_AUTODETECT_CONTROL = 0x7128, RV620_DACB_AUTODETECT_STATUS = 0x7034, RV620_DACB_FORCE_OUTPUT_CNTL = 0x713C, RV620_DACB_FORCE_DATA = 0x7140, RV620_DACB_POWERDOWN = 0x7150, /* RV620_DACB_CONTROL1 moved */ RV620_DACB_CONTROL2 = 0x7158, RV620_DACB_COMPARATOR_ENABLE = 0x715C, RV620_DACB_CONTROL1 = 0x7ff4, /* DAC common */ RV620_DAC_COMPARATOR_MISC = 0x7da4, RV620_DAC_COMPARATOR_OUTPUT = 0x7da8, /* 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) */ /* RV62x I2C */ RV62_GENERIC_I2C_CONTROL = 0x7d80, /* (RW) */ RV62_GENERIC_I2C_INTERRUPT_CONTROL = 0x7d84, /* (RW) */ RV62_GENERIC_I2C_STATUS = 0x7d88, /* (RW) */ RV62_GENERIC_I2C_SPEED = 0x7d8c, /* (RW) */ RV62_GENERIC_I2C_SETUP = 0x7d90, /* (RW) */ RV62_GENERIC_I2C_TRANSACTION = 0x7d94, /* (RW) */ RV62_GENERIC_I2C_DATA = 0x7d98, /* (RW) */ RV62_GENERIC_I2C_PIN_SELECTION = 0x7d9c, /* (RW) */ RV62_DC_GPIO_DDC4_MASK = 0x7e20, /* (RW) */ RV62_DC_GPIO_DDC1_MASK = 0x7e40, /* (RW) */ RV62_DC_GPIO_DDC2_MASK = 0x7e50, /* (RW) */ RV62_DC_GPIO_DDC3_MASK = 0x7e60, /* (RW) */ /* HPD */ DC_GPIO_HPD_Y = 0x7E9C }; typedef enum _chipType { RHD_R500 = 1, RHD_RS690, RHD_R600, RHD_RV620 } chipType; typedef enum dacOutput { DAC_NONE, DAC_VGA, DAC_SVIDEO, DAC_COMPOSITE, DAC_COMPONENT } dacOutput; /* for RHD_R500/R600/RS690/RV620 */ 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; unsigned char **command_table = NULL; int num_command_table_entries = 0; unsigned char * AtomBiosGetDataFromCodeTable(unsigned char **tablelist, int n, short *size); /* * 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, 0x793F, 2, RHD_RS690}, { 0x1002, 0x7941, 2, RHD_RS690}, { 0x1002, 0x7942, 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, 0x9405, 2, RHD_R600}, { 0x1002, 0x940A, 2, RHD_R600}, { 0x1002, 0x940B, 2, RHD_R600}, { 0x1002, 0x940F, 2, RHD_R600}, { 0x1002, 0x94C0, 2, RHD_R600}, { 0x1002, 0x94C1, 2, RHD_R600}, { 0x1002, 0x94C3, 2, RHD_R600}, { 0x1002, 0x94C4, 2, RHD_R600}, { 0x1002, 0x94C5, 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, 0x94CC, 2, RHD_R600}, { 0x1002, 0x9500, 2, RHD_R600}, { 0x1002, 0x9501, 2, RHD_R600}, { 0x1002, 0x9505, 2, RHD_R600}, { 0x1002, 0x9507, 2, RHD_R600}, { 0x1002, 0x950F, 2, RHD_R600}, { 0x1002, 0x9511, 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}, { 0x1002, 0x958C, 2, RHD_R600}, { 0x1002, 0x958D, 2, RHD_R600}, { 0x1002, 0x958E, 2, RHD_R600}, { 0x1002, 0x9598, 2, RHD_RV620}, { 0x1002, 0x95C5, 2, RHD_RV620}, { 0x1002, 0x9612, 2, RHD_RV620}, { 0, 0, 0, 0 } }; /* * */ #define LEN 16 void dprint(unsigned char *start, unsigned long size) { unsigned int i; unsigned int count = LEN; char *c = (char *)start; while (size) { char *d = c; printf(" "); if (size < LEN) count = size; size -= count; for (i = 0; i 32) && (((CARD8)(*c)) < 128)) ? (unsigned char) (*(c)): '.'); c++; } printf("\n"); } printf("\n"); } /* * */ 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) { CARD32 ret = *(volatile CARD32 *)((CARD8 *) map + offset); #ifdef DEBUG fprintf(stderr, "0x%x = RegRead(0x%x)\n",ret,offset); #endif return ret; } /* * */ void RegWrite(void *map, int offset, CARD32 value) { #ifdef DEBUG fprintf(stderr, "RegWrite(0x%x, 0x%x)\n",offset,value); #endif *(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 dacOutput DACLoadDetect(void *map, Bool tv, int dac) { CARD32 CompEnable, Control1, Control2, DetectControl, Enable; CARD8 ret; unsigned int offset = 0; if (dac) offset = 0x200; CompEnable = RegRead(map, offset + DACA_COMPARATOR_ENABLE); Control1 = RegRead(map, offset + DACA_CONTROL1); Control2 = RegRead(map, offset + DACA_CONTROL2); DetectControl = RegRead(map, offset + DACA_AUTODETECT_CONTROL); Enable = RegRead(map, offset + DACA_ENABLE); RegWrite(map, offset + DACA_ENABLE, 1); RegMask(map, offset + DACA_AUTODETECT_CONTROL, 0, 0x3); RegMask(map, offset + DACA_CONTROL2, 0, 0xff0000); RegMask(map, offset + DACA_CONTROL2, 0, 0x1); RegMask(map, offset + DACA_CONTROL2, tv ? 0x100 : 0, 0x100); RegWrite(map, offset + DACA_FORCE_DATA, 0); RegMask(map, offset + DACA_CONTROL2, 0x1, 0x1); RegMask(map, offset + DACA_COMPARATOR_ENABLE, 0x00070000, 0x00070000); RegWrite(map, offset + DACA_CONTROL1, 0x00050802); RegMask(map, offset + DACA_POWERDOWN, 0, 0x1); /* Shut down Bandgap Voltage Reference Power */ usleep(5); RegMask(map, offset + DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */ RegWrite(map, offset + DACA_FORCE_DATA, 0x1e6); /* 486 out of 1024 */ usleep(200); RegMask(map, offset + DACA_POWERDOWN, 0x01010100, 0x01010100); /* Enable RGB */ usleep(88); RegMask(map, offset + DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */ RegMask(map, offset + 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, offset + DACA_COMPARATOR_OUTPUT) & 0x0E) >> 1; #ifdef DEBUG fprintf(stderr, "DAC%s: %x %s\n", dac ? "B" : "A", ret, tv ? "TV" : ""); #endif RegMask(map, offset + DACA_COMPARATOR_ENABLE, CompEnable, 0x00FFFFFF); RegWrite(map, offset + DACA_CONTROL1, Control1); RegMask(map, offset + DACA_CONTROL2, Control2, 0x1FF); RegMask(map, offset + DACA_AUTODETECT_CONTROL, DetectControl, 0xFF); RegMask(map, offset + DACA_ENABLE, Enable, 0xFF); switch (ret & 0x7) { case 0x7: if (tv) return DAC_COMPONENT; else return DAC_VGA; case 0x1: if (tv) return DAC_COMPOSITE; else return DAC_NONE; case 0x6: if (tv) return DAC_SVIDEO; else return DAC_NONE; default: return DAC_NONE; } } /* * */ static dacOutput RV620DACLoadDetect(void *map, Bool tv, int dac) { CARD32 offset = 0; CARD32 ret; CARD32 DetectControl, AutodetectIntCtl, ForceData, Control1, Control2, CompEnable; if (dac == 1) offset = 0x100; Control1 = RegRead(map, offset + RV620_DACA_CONTROL1); /* 7ef4 */ Control2 = RegRead(map, offset + RV620_DACA_CONTROL2); /* 7058 */ ForceData = RegRead(map, offset + RV620_DACA_FORCE_DATA); AutodetectIntCtl = RegRead(map, offset + RV620_DACA_AUTODETECT_INT_CONTROL); DetectControl = RegRead(map, offset + RV620_DACA_AUTODETECT_CONTROL); CompEnable = RegRead(map, offset + RV620_DACA_COMPARATOR_ENABLE); #if 0 if (RegRead(map, offset + 0x7000) & 0x01) { CARD32 my_offset = 0; switch (RegRead(map, offset + 0x7004) & 0x3) { case 0: break; case 1: my_offset = 0x200; break; case 2: switch (RegRead(map, offset + 0x60fc) & 0x1) { case 0: break; case 1: my_offset = 0x200; break; } break; } if (RegRead(map, my_offset + 0x6080) & 0x1) { while (!(RegRead(map, my_offset + 0x609c) & 0x02)) {}; while (!(RegRead(map, my_offset + 0x609c) & 0x01)) {}; } } #endif if (tv) RegMask(map, offset + RV620_DACA_CONTROL2, 0x100, 0xff00); /* TV on */ else RegMask(map, offset + RV620_DACA_CONTROL2, 0x00, 0xff00); /* TV off */ RegMask(map, offset + RV620_DACA_FORCE_DATA, 0x18, 0xffff); /* ack autodetect */ RegMask(map, offset + RV620_DACA_AUTODETECT_INT_CONTROL, 0x01, 0x01); /* autodetect off */ RegMask(map, offset + RV620_DACA_AUTODETECT_CONTROL, 0x00, 0xff); /* bandgap */ RegMask(map, offset + RV620_DACA_CONTROL1, dac ? 0x2502 : 0x2002, 0xffff); /* DAC RGB async enable */ RegMask(map, offset + RV620_DACA_CONTROL2, 0x1, 0x1); /* enable r/g/b comparators, disable D/SDET ref */ RegMask(map, offset + RV620_DACA_COMPARATOR_ENABLE, 0x70000, 0x070101); usleep(100); /* check for connection */ RegMask(map, offset + RV620_DACA_AUTODETECT_CONTROL, 0x01, 0xff); usleep(32); ret = RegRead(map, offset + RV620_DACA_AUTODETECT_STATUS); RegWrite(map, offset + RV620_DACA_AUTODETECT_CONTROL, DetectControl); RegWrite(map, offset + RV620_DACA_CONTROL1, Control1); RegWrite(map, offset + RV620_DACA_CONTROL2, Control2); RegWrite(map, offset + RV620_DACA_FORCE_DATA, ForceData); RegWrite(map, offset + RV620_DACA_AUTODETECT_INT_CONTROL, AutodetectIntCtl); #ifdef DEBUG fprintf(stderr, "DAC%i: ret = 0x%x %s\n",dac,ret,tv ? "TV" : ""); #endif if (!tv) return ((ret & 0x111) ? DAC_VGA : DAC_NONE); switch (ret & 0x1010100) { case 0x1010100: if (tv) return DAC_COMPONENT; case 0x1000000: return DAC_COMPOSITE; case 0x10100: return DAC_SVIDEO; default: return DAC_NONE; } } /* * */ 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) { dacOutput DACA = DAC_NONE, DACB = DAC_NONE, TVA = DAC_NONE, TVB = DAC_NONE; Bool TMDSA; switch (ChipType) { case RHD_R500: case RHD_RS690: case RHD_R600: DACA = DACLoadDetect(map, FALSE, 0); DACB = DACLoadDetect(map, FALSE, 1); TVA = DACLoadDetect(map, TRUE, 0); TVB = DACLoadDetect(map, TRUE, 1); break; case RHD_RV620: DACA = RV620DACLoadDetect(map, FALSE, 0); DACB = RV620DACLoadDetect(map, FALSE, 1); TVA = RV620DACLoadDetect(map, TRUE, 0); TVB = RV620DACLoadDetect(map, TRUE, 1); break; } TMDSA =TMDSALoadDetect(map); printf(" Load Detection:"); if (!DACA && !DACB && !TMDSA && !TVA && !TVB) printf(" RHD_OUTPUT_NONE "); else { if (DACA == DAC_VGA) printf(" RHD_OUTPUT_DACA"); if (DACB == DAC_VGA) printf(" RHD_OUTPUT_DACB"); switch (TVA) { case DAC_SVIDEO: printf(" RHD_OUTPUT_DACA_TV_SVIDEO"); break; case DAC_COMPOSITE: printf(" RHD_OUTPUT_DACA_TV_COMPOSITE"); break; case DAC_COMPONENT: if (!DACA) printf(" RHD_OUTPUT_DACA_TV_COMPONENT"); break; default: break; } switch (TVB) { case DAC_SVIDEO: printf(" RHD_OUTPUT_DACB_TV_SVIDEO"); break; case DAC_COMPOSITE: printf(" RHD_OUTPUT_DACB_TV_COMPOSITE"); break; case DAC_COMPONENT: if (!DACB) printf(" RHD_OUTPUT_DACB_TV_COMPONENT"); break; default: break; } if (TMDSA) printf(" RHD_OUTPUT_TMDSA"); } printf("\n"); } /* * */ CARD32 getDDCSpeed(void) { CARD32 clock, ref_clk, ret; switch (AtomData.FirmwareInfoVersion.crev) { case 1: clock = AtomData.FirmwareInfo.FirmwareInfo->ulDefaultEngineClock; ref_clk = AtomData.FirmwareInfo.FirmwareInfo->usReferenceClock; break; case 2: clock = AtomData.FirmwareInfo.FirmwareInfo_V_1_2->ulDefaultEngineClock; ref_clk = AtomData.FirmwareInfo.FirmwareInfo_V_1_2->usReferenceClock; break; case 3: clock = AtomData.FirmwareInfo.FirmwareInfo_V_1_3->ulDefaultEngineClock; ref_clk = AtomData.FirmwareInfo.FirmwareInfo_V_1_3->usReferenceClock; break; case 4: clock = AtomData.FirmwareInfo.FirmwareInfo_V_1_4->ulDefaultEngineClock; ref_clk = AtomData.FirmwareInfo.FirmwareInfo_V_1_4->usReferenceClock; break; default: /* no AtomBIOS info; use save default */ clock = 70000; ref_clk = 270; } clock *= 10; ref_clk *= 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; case RHD_RV620: ret = (ref_clk) / (4 * 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 = 0; 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 R6xxI2CWriteRead(void *map, CARD8 line, CARD8 slave, unsigned char *WriteBuffer, int nWrite, unsigned char *ReadBuffer, int nRead) { Bool ret = FALSE; CARD32 data = 0; int idx = 1; enum { TRANS_WRITE_READ, TRANS_WRITE, TRANS_READ } trans; if (nWrite > 0 && nRead > 0) { trans = TRANS_WRITE_READ; } else if (nWrite > 0) { trans = TRANS_WRITE; } else if (nRead > 0) { trans = TRANS_READ; } else { /* for bus probing */ trans = TRANS_WRITE; } if (!R6xxI2CSetupStatus(map, line)) return FALSE; RegMask(map, R6_DC_I2C_CONTROL, (trans == TRANS_WRITE_READ) ? (1 << 20) : 0, R6_DC_I2C_TRANSACTION_COUNT); /* 2 or 1 Transaction */ RegMask(map, R6_DC_I2C_TRANSACTION0, R6_DC_I2C_STOP_ON_NACK0 | (trans == TRANS_READ ? R6_DC_I2C_RW0 : 0) | R6_DC_I2C_START0 | (trans == TRANS_WRITE_READ ? 0 : R6_DC_I2C_STOP0 ) | ((trans == TRANS_READ ? nRead : nWrite) << 16), 0xffffff); if (trans == TRANS_WRITE_READ) RegMask(map, R6_DC_I2C_TRANSACTION1, nRead << 16 | R6_DC_I2C_RW1 | R6_DC_I2C_START1 | R6_DC_I2C_STOP1, 0xffffff); /* read */ data = R6_DC_I2C_INDEX_WRITE | (((slave & 0xfe) | (trans == TRANS_READ ? 1 : 0)) << 8 ) | (0 << 16); RegWrite(map, R6_DC_I2C_DATA, data); if (trans != TRANS_READ) { /* we have bytes to write */ while (nWrite--) { data = R6_DC_I2C_INDEX_WRITE | ( *(WriteBuffer++) << 8 ) | (idx++ << 16); RegWrite(map, R6_DC_I2C_DATA, data); } } if (trans == TRANS_WRITE_READ) { /* we have bytes to read after write */ data = R6_DC_I2C_INDEX_WRITE | ((slave | 0x1) << 8) | (idx++ << 16); RegWrite(map, R6_DC_I2C_DATA, data); } /* Go! */ RegMask(map, R6_DC_I2C_CONTROL, R6_DC_I2C_GO, R6_DC_I2C_GO); if (R6xxI2CStatus(map)) { /* Hopefully this doesn't write data to index */ RegWrite(map, R6_DC_I2C_DATA, R6_DC_I2C_INDEX_WRITE | R6_DC_I2C_DATA_RW | /* idx++ */3 << 16); while (nRead--) { data = RegRead(map, R6_DC_I2C_DATA); *(ReadBuffer++) = (data >> 8) & 0xff; } ret = TRUE; } else return FALSE; RegMask(map, R6_DC_I2C_CONTROL, 0x2, 0xff); usleep(10); RegWrite(map, R6_DC_I2C_CONTROL, 0); return ret; } /* * */ 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 */ #ifdef DEBUG fprintf(stderr,"GPIO line DDC%i: 0x%x\n",line, AtomData .GPIO_I2C_Info->asGPIO_Info[line & 0xf].usClkMaskRegisterIndex); #endif 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 int RS69xI2CWriteRead(void *map, CARD8 line, CARD8 slave, unsigned char *WriteBuffer, int nWrite, unsigned char *ReadBuffer, int nRead) { Bool ret = FALSE; CARD32 data = 0; int idx = 1; enum { TRANS_WRITE_READ, TRANS_WRITE, TRANS_READ } trans; if (nWrite > 0 && nRead > 0) { trans = TRANS_WRITE_READ; } else if (nWrite > 0) { trans = TRANS_WRITE; } else if (nRead > 0) { trans = TRANS_READ; } else { /* for bus probing */ trans = TRANS_WRITE; } if (!RS69I2CSetupStatus(map, line)) return FALSE; RegMask(map, RS69_DC_I2C_CONTROL, (trans == TRANS_WRITE_READ) ? (1 << 20) : 0, RS69_DC_I2C_TRANSACTION_COUNT); /* 2 or 1 Transaction */ RegMask(map, RS69_DC_I2C_TRANSACTION0, RS69_DC_I2C_STOP_ON_NACK0 | (trans == TRANS_READ ? RS69_DC_I2C_RW0 : 0) | RS69_DC_I2C_START0 | (trans == TRANS_WRITE_READ ? 0 : RS69_DC_I2C_STOP0 ) | ((trans == TRANS_READ ? nRead : nWrite) << 16), 0xffffff); if (trans == TRANS_WRITE_READ) RegMask(map, RS69_DC_I2C_TRANSACTION1, nRead << 16 | RS69_DC_I2C_RW1 | RS69_DC_I2C_START1 | RS69_DC_I2C_STOP1, 0xffffff); /* read */ data = RS69_DC_I2C_INDEX_WRITE | (((slave & 0xfe) | (trans == TRANS_READ ? 1 : 0)) << 8 ) | (0 << 16); RegWrite(map, RS69_DC_I2C_DATA, data); if (trans != TRANS_READ) { /* we have bytes to write */ while (nWrite--) { data = RS69_DC_I2C_INDEX_WRITE | ( *(WriteBuffer++) << 8 ) | (idx++ << 16); RegWrite(map, RS69_DC_I2C_DATA, data); } } if (trans == TRANS_WRITE_READ) { /* we have bytes to read after write */ data = RS69_DC_I2C_INDEX_WRITE | ((slave | 0x1) << 8) | (idx++ << 16); RegWrite(map, RS69_DC_I2C_DATA, data); } /* Go! */ RegMask(map, RS69_DC_I2C_CONTROL, RS69_DC_I2C_GO, RS69_DC_I2C_GO); if (RS69I2CStatus(map)) { /* Hopefully this doesn't write data to index */ RegWrite(map, RS69_DC_I2C_DATA, RS69_DC_I2C_INDEX_WRITE | RS69_DC_I2C_DATA_RW | /* idx++ */3 << 16); while (nRead--) { data = RegRead(map, RS69_DC_I2C_DATA); *(ReadBuffer++) = (data >> 8) & 0xff; } ret = TRUE; } RegMask(map, RS69_DC_I2C_CONTROL, 0x2, 0xff); usleep(10); RegWrite(map, RS69_DC_I2C_CONTROL, 0); return ret; } /* * */ 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 R5xxI2CSetupStatus(void *map, int channel) { 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); 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); 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); break; default: return FALSE; } return TRUE; } /* * */ 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 int R5xxDDCProbe(void *map, int Channel, unsigned char slave) { Bool ret = FALSE; CARD32 SaveControl1, save_494; CARD16 prescale; prescale = getDDCSpeed(); if (!prescale) return FALSE; if (!R5xxI2CSetupStatus(map, Channel)) 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; } /* * */ Bool R5xxI2CWriteReadChunk(void *map, CARD8 line, CARD8 slave, unsigned char *WriteBuffer, int nWrite, unsigned char *ReadBuffer, int nRead) { int prescale = getDDCSpeed(); CARD32 save_I2C_CONTROL1, save_494; CARD32 tmp32; Bool ret = TRUE; RegMask(map, 0x28, 0x200, 0x200); save_I2C_CONTROL1 = 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, (line & 0x0f) << 16 | R5_DC_I2C_EN, R5_DC_I2C_PIN_SELECT | R5_DC_I2C_EN); if (nWrite || !nRead) { /* special case for bus probing */ /* * chip can't just write the slave address without data. * Add a dummy byte. */ RegWrite(map, R5_DC_I2C_CONTROL2, prescale << 16 | (nWrite ? nWrite : 1) << 8 | 0x01); /* addr_cnt: 1 */ RegMask(map, R5_DC_I2C_CONTROL3, 0x30 << 24, 0xff << 24); /* time limit 30 */ RegWrite(map, R5_DC_I2C_DATA, slave); /* Add dummy byte */ if (!nWrite) RegWrite(map, R5_DC_I2C_DATA, 0); else while (nWrite--) RegWrite(map, R5_DC_I2C_DATA, *WriteBuffer++); 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); if ((ret = R5xxI2CStatus(map))) RegMask(map, R5_DC_I2C_STATUS1,R5_DC_I2C_DONE, 0xff); else ret = FALSE; } if (ret && nRead) { RegWrite(map, R5_DC_I2C_DATA, slave | 1); /*slave*/ RegWrite(map, R5_DC_I2C_CONTROL2, prescale << 16 | nRead << 8 | 0x01); /* addr_cnt: 1 */ RegMask(map, R5_DC_I2C_CONTROL1, R5_DC_I2C_START | R5_DC_I2C_STOP | R5_DC_I2C_RECEIVE, 0xff); RegMask(map, R5_DC_I2C_STATUS1, R5_DC_I2C_GO, 0xff); if ((ret = R5xxI2CStatus(map))) { RegMask(map, R5_DC_I2C_STATUS1, R5_DC_I2C_DONE, 0xff); while (nRead--) { *(ReadBuffer++) = (CARD8)RegRead(map, R5_DC_I2C_DATA); } } else ret = FALSE; } 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, save_I2C_CONTROL1); RegWrite(map,0x494, save_494); tmp32 = RegRead(map,0x28); RegWrite(map,0x28, tmp32 & 0xfffffdff); return ret; } /* * */ static Bool R5xxI2CWriteRead(void *map, CARD8 line, CARD8 slave, unsigned char *WriteBuffer, int nWrite, unsigned char *ReadBuffer, int nRead) { /* * Since the transaction buffer can only hold * 15 bytes (+ the slave address) we bail out * on every transaction that is bigger unless * it's a read transaction following a write * transaction sending just one byte. * In this case we assume, that this byte is * an offset address. Thus we will restart * the transaction after 15 bytes sending * a new offset. */ if (nWrite > 15 || (nRead > 15 && nWrite != 1)) { fprintf(stderr, "%s: Currently only I2C transfers with " "maximally 15bytes are supported\n", __func__); return FALSE; } if (nRead > 15) { unsigned char offset = *WriteBuffer; while (nRead) { int n = nRead > 15 ? 15 : nRead; if (!R5xxI2CWriteReadChunk(map, line, slave, &offset, 1, ReadBuffer, n)) return FALSE; ReadBuffer += n; nRead -= n; offset += n; } return TRUE; } else return R5xxI2CWriteReadChunk(map, line, slave, WriteBuffer, nWrite, ReadBuffer, nRead); } /* RV620 */ enum rv620I2CBits { /* GENERIC_I2C_CONTROL */ RV62_DC_I2C_GO = (0x1 << 0), RV62_GENERIC_I2C_GO = (0x1 << 0), RV62_GENERIC_I2C_SOFT_RESET = (0x1 << 1), RV62_GENERIC_I2C_SEND_RESET = (0x1 << 2), /* GENERIC_I2C_INTERRUPT_CONTROL */ RV62_GENERIC_I2C_DONE_INT = (0x1 << 0), RV62_GENERIC_I2C_DONE_ACK = (0x1 << 1), RV62_GENERIC_I2C_DONE_MASK = (0x1 << 2), /* GENERIC_I2C_STATUS */ RV62_GENERIC_I2C_STATUS_BIT = (0xf << 0), RV62_GENERIC_I2C_DONE = (0x1 << 4), RV62_GENERIC_I2C_ABORTED = (0x1 << 5), RV62_GENERIC_I2C_TIMEOUT = (0x1 << 6), RV62_GENERIC_I2C_STOPPED_ON_NACK = (0x1 << 9), RV62_GENERIC_I2C_NACK = (0x1 << 10), /* GENERIC_I2C_SPEED */ RV62_GENERIC_I2C_THRESHOLD = (0x3 << 0), RV62_GENERIC_I2C_DISABLE_FILTER_DURING_STALL = (0x1 << 4), RV62_GENERIC_I2C_PRESCALE = (0xffff << 16), /* GENERIC_I2C_SETUP */ RV62_GENERIC_I2C_DATA_DRIVE_EN = (0x1 << 0), RV62_GENERIC_I2C_DATA_DRIVE_SEL = (0x1 << 1), RV62_GENERIC_I2C_CLK_DRIVE_EN = (0x1 << 7), RV62_GENERIC_I2C_INTRA_BYTE_DELAY = (0xff << 8), RV62_GENERIC_I2C_TIME_LIMIT = (0xff << 24), /* GENERIC_I2C_TRANSACTION */ RV62_GENERIC_I2C_RW = (0x1 << 0), RV62_GENERIC_I2C_STOP_ON_NACK = (0x1 << 8), RV62_GENERIC_I2C_ACK_ON_READ = (0x1 << 9), RV62_GENERIC_I2C_START = (0x1 << 12), RV62_GENERIC_I2C_STOP = (0x1 << 13), RV62_GENERIC_I2C_COUNT = (0xf << 16), /* GENERIC_I2C_DATA */ RV62_GENERIC_I2C_DATA_RW = (0x1 << 0), RV62_GENERIC_I2C_DATA_BIT = (0xff << 8), RV62_GENERIC_I2C_INDEX = (0xf << 16), RV62_GENERIC_I2C_INDEX_WRITE = (0x1 << 31), /* GENERIC_I2C_PIN_SELECTION */ RV62_GENERIC_I2C_SCL_PIN_SEL = (0x7f << 0), RV62_GENERIC_I2C_SDA_PIN_SEL = (0x7f << 8), }; /* * */ static Bool RV620I2CStatus(void *map) { int count = 50; volatile CARD32 val; while (--count) { usleep(10); val = RegRead(map, RV62_GENERIC_I2C_STATUS); #ifdef DEBUG fprintf(stderr,"SW_STATUS: 0x%x %i\n",(unsigned int)val,count); #endif if (val & RV62_GENERIC_I2C_DONE) break; } RegMask(map, RV62_GENERIC_I2C_INTERRUPT_CONTROL, 0x2, 0xff); if (!count || (val & (RV62_GENERIC_I2C_STOPPED_ON_NACK | RV62_GENERIC_I2C_NACK | RV62_GENERIC_I2C_TIMEOUT | RV62_GENERIC_I2C_ABORTED))) return FALSE; /* 2 */ return TRUE; /* 1 */ } /* * */ static Bool RV620I2CSetupStatus(void *map, int line, int prescale) { /* CARD32 reg_7d9c[] = { 0x1, 0x0203, 0x0405, 0x0607 }; */ CARD32 reg_7d9c; unsigned char *table; short size = 0; int i = 0; if (line > 3) return FALSE; table = AtomBiosGetDataFromCodeTable(command_table, 0x36, &size); while (i < size) { if (table[i] == line) { reg_7d9c = table[i + 3] << 8 | table[i + 2]; #ifdef DEBUG fprintf(stderr, "Line[%i] = 0x%4.4x\n",line, reg_7d9c); #endif break; } i += 4; } if (i >= size) return FALSE; RegWrite(map, 0x7e40, 0); RegWrite(map, 0x7e50, 0); RegWrite(map, 0x7e60, 0); RegWrite(map, 0x7e20, 0); RegWrite(map, RV62_GENERIC_I2C_PIN_SELECTION, reg_7d9c); RegMask(map, RV62_GENERIC_I2C_SPEED, (prescale & 0xffff) << 16 | 0x02, 0xffff00ff); RegWrite(map, RV62_GENERIC_I2C_SETUP, 0x30000000); RegMask(map, RV62_GENERIC_I2C_INTERRUPT_CONTROL, RV62_GENERIC_I2C_DONE_ACK, RV62_GENERIC_I2C_DONE_ACK); return TRUE; } /* * */ static Bool RV620I2CTransaction(void *map, CARD8 slave, Bool Write, unsigned char *Buffer, int count) { Bool Start = TRUE; #define MAX 8 while (count > 0) { int num; int idx = 0; CARD32 data = 0; if (count > MAX) { num = MAX; RegMask(map, RV62_GENERIC_I2C_TRANSACTION, (MAX - (((Start) ? 0 : 1))) << 16 | RV62_GENERIC_I2C_STOP_ON_NACK | RV62_GENERIC_I2C_ACK_ON_READ | (Start ? RV62_GENERIC_I2C_START : 0) | (!Write ? RV62_GENERIC_I2C_RW : 0 ), 0xFFFFFF); } else { num = count; data = ( count - (((Start) ? 0 : 1)) ) << 16 | RV62_GENERIC_I2C_STOP_ON_NACK | RV62_GENERIC_I2C_STOP | (Start ? RV62_GENERIC_I2C_START : 0) | (!Write ? RV62_GENERIC_I2C_RW : 0); RegMask(map, RV62_GENERIC_I2C_TRANSACTION, data, 0xFFFFFF); } if (Start) { data = RV62_GENERIC_I2C_INDEX_WRITE | (((slave & 0xfe) | ( Write ? 0 : 1)) << 8) | (idx++ << 16); RegWrite(map, RV62_GENERIC_I2C_DATA, data); } if (Write) { while (num--) { data = RV62_GENERIC_I2C_INDEX_WRITE | (idx++ << 16) | *(Buffer++) << 8; RegWrite(map, RV62_GENERIC_I2C_DATA, data); } RegMask(map, RV62_GENERIC_I2C_CONTROL, RV62_GENERIC_I2C_GO, RV62_GENERIC_I2C_GO); if (!RV620I2CStatus(map)) return FALSE; } else { RegMask(map, RV62_GENERIC_I2C_CONTROL, RV62_GENERIC_I2C_GO, RV62_GENERIC_I2C_GO); if (!RV620I2CStatus(map)) return FALSE; RegWrite(map, RV62_GENERIC_I2C_DATA, RV62_GENERIC_I2C_INDEX_WRITE | (idx++ << 16) | RV62_GENERIC_I2C_RW); while (num--) { data = RegRead(map, RV62_GENERIC_I2C_DATA); *(Buffer++) = (CARD8)((data >> 8) & 0xff); } } Start = FALSE; count -= MAX; } return TRUE; } /* * */ static Bool RV620I2CWriteRead(void *map, CARD8 line, CARD8 slave, unsigned char *WriteBuffer, int nWrite, unsigned char *ReadBuffer, int nRead) { int prescale = getDDCSpeed(); if (!prescale) return FALSE; RV620I2CSetupStatus(map, line, prescale); if (!nWrite && !nRead) return RV620I2CTransaction(map, slave, TRUE, (unsigned char *)"", 1); if (nWrite) if (!RV620I2CTransaction(map, slave, TRUE, WriteBuffer, nWrite)) return FALSE; if (nRead) if (!RV620I2CTransaction(map, slave, FALSE, ReadBuffer, nRead)) return FALSE; return TRUE; } /* * */ static Bool RV620DDCProbe(void *map, int Channel, unsigned char slave) { return RV620I2CWriteRead(map, Channel, slave, NULL, 0, NULL, 0); } /* * */ static Bool DDCProbe(void *map, int Channel, unsigned char slave, unsigned char *data, int count) { Bool ret; unsigned char offset = 0; switch (ChipType) { case RHD_R500: if (( ret = R5xxDDCProbe(map, Channel, slave)) && count > 0) { ret = R5xxI2CWriteRead(map, Channel, slave, &offset, 1, data, count); }; return ret; case RHD_RS690: if ((ret = RS69DDCProbe(map, Channel, slave)) && count > 0) { ret = RS69xI2CWriteRead(map, Channel, slave, &offset, 1, data, count); }; return ret; case RHD_R600: if ((ret = R6xxDDCProbe(map, Channel, slave)) && count > 0) { ret = R6xxI2CWriteRead(map, Channel, slave, &offset, 1, data, count); }; return ret; case RHD_RV620: if ((ret = RV620DDCProbe(map, Channel, slave)) && count > 0) { ret = RV620I2CWriteRead(map, Channel, slave, &offset, 1, data, count); }; return ret; default: return FALSE; } } /* * */ #define EDID_SLAVE 0xA0 static void DDCReport(void *map) { Bool Chan0, Chan1, Chan2, Chan3; Chan0 = DDCProbe(map, 0, EDID_SLAVE, NULL, 0); Chan1 = DDCProbe(map, 1, EDID_SLAVE, NULL, 0); Chan2 = DDCProbe(map, 2, EDID_SLAVE, NULL, 0); if (ChipType >= RHD_R600) Chan3 = DDCProbe(map, 3, EDID_SLAVE, NULL, 0); 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 count) { int channel; unsigned char slave; int max_chan = ((ChipType >= RHD_R600) ? 3 : 2); unsigned char *data = NULL; if (count) data = alloca(count); for (channel = 0; channel < max_chan; channel ++) { int state = 0; for (slave = 0x8; slave < 0x78; slave++ ) { if (DDCProbe(map, channel, slave << 1, data, count)) { if (state == 0) { printf(" DDC Line[%i]: Slaves: ", channel); if (!data) state = 1; } printf("%x ", slave << 1); if (data) { printf("\n"); dprint(data, count); } } } 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) & 0x10; 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, int *code_offset) { if (AnalyzeCommonHdr(&hdr->sHeader) == -1) { return FALSE; } *data_offset = hdr->usMasterDataTableOffset; *code_offset = hdr->usMasterCommandTableOffset; 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" " -x num: dump num bytes from available i2c channels\n" " PCI-tag: bus:dev.func\n\n", progname); } /* * */ struct atomCodeDataTableHeader { unsigned char signature; unsigned short size; }; #define CODE_DATA_TABLE_SIGNATURE 0x7a #define ATOM_EOT_COMMAND 0x5b unsigned char * AtomBiosGetDataFromCodeTable(unsigned char **tablelist, int n, short *size) { ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *header = (ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *) tablelist[n]; unsigned char *code; int i; if (!header) return NULL; if (!AnalyzeCommonHdr(&header->CommonHeader)) return NULL; if (!GetAtomBiosTableRevisionAndSize(&header->CommonHeader,NULL,NULL,size)) return NULL; code = (unsigned char *)header; #ifdef DEBUG fprintf(stderr, "table[%2.2i].size = 0x%3.3x bytes\n",n,*size); #endif for (i = sizeof(ATOM_COMMON_ROM_COMMAND_TABLE_HEADER); i < *size - 1; i++) { if (code[i] == ATOM_EOT_COMMAND && code[i+1] == CODE_DATA_TABLE_SIGNATURE) { struct atomCodeDataTableHeader *dt = (struct atomCodeDataTableHeader *)&code[i]; int diff; diff = *size - (i + 1) + sizeof(struct atomCodeDataTableHeader) + SHORT(dt->size); if (diff < 0) { fprintf(stderr, "Data table in command table %i extends %i bytes " "beyond command table size\n", n, -diff); return NULL; } else { #ifdef DEBUG fprintf(stderr, "code data table size: 0x%4.4x\n",SHORT(dt->size)); dprint(&code[i + sizeof(struct atomCodeDataTableHeader)], SHORT(dt->size)); #endif return &code[i + sizeof(struct atomCodeDataTableHeader)]; } } } return NULL; } /* * */ unsigned char ** AtomBiosAnalyzeCommandTable(ATOM_MASTER_COMMAND_TABLE *table, unsigned char *base, int *num) { short size; int i; unsigned char **tablelist = NULL; unsigned short offset; *num = sizeof(ATOM_MASTER_LIST_OF_COMMAND_TABLES)/sizeof(USHORT); if (!AnalyzeCommonHdr(&table->sHeader)) return NULL; if (!GetAtomBiosTableRevisionAndSize(&table->sHeader,NULL,NULL,&size)) return NULL; if ((tablelist = (unsigned char **)calloc(*num, sizeof (char *)))) { for (i = 0; i < *num; i++) if ((offset = ((USHORT *)&(table->ListOfCommandTables))[i])) { #ifdef DEBUG fprintf(stderr, "CommandTableEntry[%2.2i] = 0x%4.4x\n",i,offset); #endif tablelist[i] = base + offset; } else tablelist[i] = NULL; } return tablelist; } /* * */ static Bool InterpretATOMBIOS(unsigned char *base) { int data_offset, code_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, &code_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; } command_table = AtomBiosAnalyzeCommandTable((ATOM_MASTER_COMMAND_TABLE *)(base + code_offset), base, &num_command_table_entries); return TRUE; } /* * */ int main(int argc, char *argv[]) { struct pci_dev *device = NULL; struct pci_access *pciAccess; struct RHDDevice *rhdDevice = NULL; int devMem; void *io; int bus, dev, func; int ret; int saved_errno; Bool deviceSet = FALSE; Bool dumpBios = FALSE, scanDDCBus = FALSE; unsigned long DumpI2CData = 0; int i; unsigned char *rombase; int size; 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("-x",argv[i],3)) { if (++i == argc || !strncmp("-", argv[i], 1)) { print_help(argv[0], "Option -x requires an argument",""); return 1; } DumpI2CData = strtol(argv[i], NULL, 0); if (DumpI2CData > 256) { fprintf(stderr, "can only dump up to 256 bytes"); return -1; } } 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 || DumpI2CData) DDCScanBus(io, DumpI2CData); FreeVBIOS(rombase, size); return 0; }