radeon_bios.c revision 209ff23f
1209ff23fSmrg/* 2209ff23fSmrg * Copyright 2004 ATI Technologies Inc., Markham, Ontario 3209ff23fSmrg * 4209ff23fSmrg * All Rights Reserved. 5209ff23fSmrg * 6209ff23fSmrg * Permission is hereby granted, free of charge, to any person obtaining 7209ff23fSmrg * a copy of this software and associated documentation files (the 8209ff23fSmrg * "Software"), to deal in the Software without restriction, including 9209ff23fSmrg * without limitation on the rights to use, copy, modify, merge, 10209ff23fSmrg * publish, distribute, sublicense, and/or sell copies of the Software, 11209ff23fSmrg * and to permit persons to whom the Software is furnished to do so, 12209ff23fSmrg * subject to the following conditions: 13209ff23fSmrg * 14209ff23fSmrg * The above copyright notice and this permission notice (including the 15209ff23fSmrg * next paragraph) shall be included in all copies or substantial 16209ff23fSmrg * portions of the Software. 17209ff23fSmrg * 18209ff23fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19209ff23fSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20209ff23fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21209ff23fSmrg * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR 22209ff23fSmrg * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23209ff23fSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24209ff23fSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25209ff23fSmrg * DEALINGS IN THE SOFTWARE. 26209ff23fSmrg */ 27209ff23fSmrg 28209ff23fSmrg#ifdef HAVE_CONFIG_H 29209ff23fSmrg#include "config.h" 30209ff23fSmrg#endif 31209ff23fSmrg 32209ff23fSmrg#include <string.h> 33209ff23fSmrg 34209ff23fSmrg#include "xf86.h" 35209ff23fSmrg#include "xf86_OSproc.h" 36209ff23fSmrg 37209ff23fSmrg#include "xf86PciInfo.h" 38209ff23fSmrg#include "radeon.h" 39209ff23fSmrg#include "radeon_reg.h" 40209ff23fSmrg#include "radeon_macros.h" 41209ff23fSmrg#include "radeon_probe.h" 42209ff23fSmrg#include "radeon_atombios.h" 43209ff23fSmrg#include "vbe.h" 44209ff23fSmrg 45209ff23fSmrgtypedef enum 46209ff23fSmrg{ 47209ff23fSmrg DDC_NONE_DETECTED, 48209ff23fSmrg DDC_MONID, 49209ff23fSmrg DDC_DVI, 50209ff23fSmrg DDC_VGA, 51209ff23fSmrg DDC_CRT2, 52209ff23fSmrg DDC_LCD, 53209ff23fSmrg DDC_GPIO, 54209ff23fSmrg} RADEONLegacyDDCType; 55209ff23fSmrg 56209ff23fSmrgtypedef enum 57209ff23fSmrg{ 58209ff23fSmrg CONNECTOR_NONE_LEGACY, 59209ff23fSmrg CONNECTOR_PROPRIETARY_LEGACY, 60209ff23fSmrg CONNECTOR_CRT_LEGACY, 61209ff23fSmrg CONNECTOR_DVI_I_LEGACY, 62209ff23fSmrg CONNECTOR_DVI_D_LEGACY, 63209ff23fSmrg CONNECTOR_CTV_LEGACY, 64209ff23fSmrg CONNECTOR_STV_LEGACY, 65209ff23fSmrg CONNECTOR_UNSUPPORTED_LEGACY 66209ff23fSmrg} RADEONLegacyConnectorType; 67209ff23fSmrg 68209ff23fSmrgstatic Bool 69209ff23fSmrgradeon_read_bios(ScrnInfoPtr pScrn) 70209ff23fSmrg{ 71209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 72209ff23fSmrg 73209ff23fSmrg#ifdef XSERVER_LIBPCIACCESS 74209ff23fSmrg if (pci_device_read_rom(info->PciInfo, info->VBIOS)) { 75209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 76209ff23fSmrg "Failed to read PCI ROM!\n"); 77209ff23fSmrg return FALSE; 78209ff23fSmrg } 79209ff23fSmrg#else 80209ff23fSmrg xf86ReadPciBIOS(0, info->PciTag, 0, info->VBIOS, RADEON_VBIOS_SIZE); 81209ff23fSmrg if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { 82209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 83209ff23fSmrg "Video BIOS not detected in PCI space!\n"); 84209ff23fSmrg if (xf86IsEntityPrimary(info->pEnt->index)) { 85209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 86209ff23fSmrg "Attempting to read Video BIOS from " 87209ff23fSmrg "legacy ISA space!\n"); 88209ff23fSmrg info->BIOSAddr = 0x000c0000; 89209ff23fSmrg xf86ReadDomainMemory(info->PciTag, info->BIOSAddr, 90209ff23fSmrg RADEON_VBIOS_SIZE, info->VBIOS); 91209ff23fSmrg } 92209ff23fSmrg } 93209ff23fSmrg#endif 94209ff23fSmrg if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) 95209ff23fSmrg return FALSE; 96209ff23fSmrg else 97209ff23fSmrg return TRUE; 98209ff23fSmrg} 99209ff23fSmrg 100209ff23fSmrgstatic Bool 101209ff23fSmrgradeon_read_unposted_bios(ScrnInfoPtr pScrn) 102209ff23fSmrg{ 103209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 104209ff23fSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 105209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 106209ff23fSmrg Bool ret; 107209ff23fSmrg 108209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Attempting to read un-POSTed bios\n"); 109209ff23fSmrg 110209ff23fSmrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 111209ff23fSmrg uint32_t viph_control = INREG(RADEON_VIPH_CONTROL); 112209ff23fSmrg uint32_t bus_cntl = INREG(RADEON_BUS_CNTL); 113209ff23fSmrg uint32_t d1vga_control = INREG(AVIVO_D1VGA_CONTROL); 114209ff23fSmrg uint32_t d2vga_control = INREG(AVIVO_D2VGA_CONTROL); 115209ff23fSmrg uint32_t vga_render_control = INREG(AVIVO_VGA_RENDER_CONTROL); 116209ff23fSmrg uint32_t rom_cntl = INREG(R600_ROM_CNTL); 117209ff23fSmrg uint32_t general_pwrmgt = INREG(R600_GENERAL_PWRMGT); 118209ff23fSmrg uint32_t low_vid_lower_gpio_cntl = INREG(R600_LOW_VID_LOWER_GPIO_CNTL); 119209ff23fSmrg uint32_t medium_vid_lower_gpio_cntl = INREG(R600_MEDIUM_VID_LOWER_GPIO_CNTL); 120209ff23fSmrg uint32_t high_vid_lower_gpio_cntl = INREG(R600_HIGH_VID_LOWER_GPIO_CNTL); 121209ff23fSmrg uint32_t ctxsw_vid_lower_gpio_cntl = INREG(R600_CTXSW_VID_LOWER_GPIO_CNTL); 122209ff23fSmrg uint32_t lower_gpio_enable = INREG(R600_LOWER_GPIO_ENABLE); 123209ff23fSmrg 124209ff23fSmrg /* disable VIP */ 125209ff23fSmrg OUTREG(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); 126209ff23fSmrg 127209ff23fSmrg /* enable the rom */ 128209ff23fSmrg OUTREG(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); 129209ff23fSmrg 130209ff23fSmrg /* Disable VGA mode */ 131209ff23fSmrg OUTREG(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | 132209ff23fSmrg AVIVO_DVGA_CONTROL_TIMING_SELECT))); 133209ff23fSmrg OUTREG(AVIVO_D2VGA_CONTROL, (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | 134209ff23fSmrg AVIVO_DVGA_CONTROL_TIMING_SELECT))); 135209ff23fSmrg OUTREG(AVIVO_VGA_RENDER_CONTROL, (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK)); 136209ff23fSmrg 137209ff23fSmrg OUTREG(R600_ROM_CNTL, ((rom_cntl & ~R600_SCK_PRESCALE_CRYSTAL_CLK_MASK) | 138209ff23fSmrg (1 << R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT) | 139209ff23fSmrg R600_SCK_OVERWRITE)); 140209ff23fSmrg 141209ff23fSmrg OUTREG(R600_GENERAL_PWRMGT, (general_pwrmgt & ~R600_OPEN_DRAIN_PADS)); 142209ff23fSmrg 143209ff23fSmrg OUTREG(R600_LOW_VID_LOWER_GPIO_CNTL, (low_vid_lower_gpio_cntl & ~0x400)); 144209ff23fSmrg 145209ff23fSmrg OUTREG(R600_MEDIUM_VID_LOWER_GPIO_CNTL, (medium_vid_lower_gpio_cntl & ~0x400)); 146209ff23fSmrg 147209ff23fSmrg OUTREG(R600_HIGH_VID_LOWER_GPIO_CNTL, (high_vid_lower_gpio_cntl & ~0x400)); 148209ff23fSmrg 149209ff23fSmrg OUTREG(R600_CTXSW_VID_LOWER_GPIO_CNTL, (ctxsw_vid_lower_gpio_cntl & ~0x400)); 150209ff23fSmrg 151209ff23fSmrg OUTREG(R600_LOWER_GPIO_ENABLE, (lower_gpio_enable | 0x400)); 152209ff23fSmrg 153209ff23fSmrg ret = radeon_read_bios(pScrn); 154209ff23fSmrg 155209ff23fSmrg /* restore regs */ 156209ff23fSmrg OUTREG(RADEON_VIPH_CONTROL, viph_control); 157209ff23fSmrg OUTREG(RADEON_BUS_CNTL, bus_cntl); 158209ff23fSmrg OUTREG(AVIVO_D1VGA_CONTROL, d1vga_control); 159209ff23fSmrg OUTREG(AVIVO_D2VGA_CONTROL, d2vga_control); 160209ff23fSmrg OUTREG(AVIVO_VGA_RENDER_CONTROL, vga_render_control); 161209ff23fSmrg OUTREG(R600_ROM_CNTL, rom_cntl); 162209ff23fSmrg OUTREG(R600_GENERAL_PWRMGT, general_pwrmgt); 163209ff23fSmrg OUTREG(R600_LOW_VID_LOWER_GPIO_CNTL, low_vid_lower_gpio_cntl); 164209ff23fSmrg OUTREG(R600_MEDIUM_VID_LOWER_GPIO_CNTL, medium_vid_lower_gpio_cntl); 165209ff23fSmrg OUTREG(R600_HIGH_VID_LOWER_GPIO_CNTL, high_vid_lower_gpio_cntl); 166209ff23fSmrg OUTREG(R600_CTXSW_VID_LOWER_GPIO_CNTL, ctxsw_vid_lower_gpio_cntl); 167209ff23fSmrg OUTREG(R600_LOWER_GPIO_ENABLE, lower_gpio_enable); 168209ff23fSmrg 169209ff23fSmrg } else if (info->ChipFamily >= CHIP_FAMILY_RV515) { 170209ff23fSmrg uint32_t seprom_cntl1 = INREG(RADEON_SEPROM_CNTL1); 171209ff23fSmrg uint32_t viph_control = INREG(RADEON_VIPH_CONTROL); 172209ff23fSmrg uint32_t bus_cntl = INREG(RADEON_BUS_CNTL); 173209ff23fSmrg uint32_t d1vga_control = INREG(AVIVO_D1VGA_CONTROL); 174209ff23fSmrg uint32_t d2vga_control = INREG(AVIVO_D2VGA_CONTROL); 175209ff23fSmrg uint32_t vga_render_control = INREG(AVIVO_VGA_RENDER_CONTROL); 176209ff23fSmrg uint32_t gpiopad_a = INREG(RADEON_GPIOPAD_A); 177209ff23fSmrg uint32_t gpiopad_en = INREG(RADEON_GPIOPAD_EN); 178209ff23fSmrg uint32_t gpiopad_mask = INREG(RADEON_GPIOPAD_MASK); 179209ff23fSmrg 180209ff23fSmrg OUTREG(RADEON_SEPROM_CNTL1, ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) | 181209ff23fSmrg (0xc << RADEON_SCK_PRESCALE_SHIFT))); 182209ff23fSmrg 183209ff23fSmrg OUTREG(RADEON_GPIOPAD_A, 0); 184209ff23fSmrg OUTREG(RADEON_GPIOPAD_EN, 0); 185209ff23fSmrg OUTREG(RADEON_GPIOPAD_MASK, 0); 186209ff23fSmrg 187209ff23fSmrg /* disable VIP */ 188209ff23fSmrg OUTREG(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); 189209ff23fSmrg 190209ff23fSmrg /* enable the rom */ 191209ff23fSmrg OUTREG(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); 192209ff23fSmrg 193209ff23fSmrg /* Disable VGA mode */ 194209ff23fSmrg OUTREG(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | 195209ff23fSmrg AVIVO_DVGA_CONTROL_TIMING_SELECT))); 196209ff23fSmrg OUTREG(AVIVO_D2VGA_CONTROL, (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | 197209ff23fSmrg AVIVO_DVGA_CONTROL_TIMING_SELECT))); 198209ff23fSmrg OUTREG(AVIVO_VGA_RENDER_CONTROL, (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK)); 199209ff23fSmrg 200209ff23fSmrg ret = radeon_read_bios(pScrn); 201209ff23fSmrg 202209ff23fSmrg /* restore regs */ 203209ff23fSmrg OUTREG(RADEON_SEPROM_CNTL1, seprom_cntl1); 204209ff23fSmrg OUTREG(RADEON_VIPH_CONTROL, viph_control); 205209ff23fSmrg OUTREG(RADEON_BUS_CNTL, bus_cntl); 206209ff23fSmrg OUTREG(AVIVO_D1VGA_CONTROL, d1vga_control); 207209ff23fSmrg OUTREG(AVIVO_D2VGA_CONTROL, d2vga_control); 208209ff23fSmrg OUTREG(AVIVO_VGA_RENDER_CONTROL, vga_render_control); 209209ff23fSmrg OUTREG(RADEON_GPIOPAD_A, gpiopad_a); 210209ff23fSmrg OUTREG(RADEON_GPIOPAD_EN, gpiopad_en); 211209ff23fSmrg OUTREG(RADEON_GPIOPAD_MASK, gpiopad_mask); 212209ff23fSmrg 213209ff23fSmrg } else { 214209ff23fSmrg uint32_t seprom_cntl1 = INREG(RADEON_SEPROM_CNTL1); 215209ff23fSmrg uint32_t viph_control = INREG(RADEON_VIPH_CONTROL); 216209ff23fSmrg uint32_t bus_cntl = INREG(RADEON_BUS_CNTL); 217209ff23fSmrg uint32_t crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL); 218209ff23fSmrg uint32_t crtc2_gen_cntl = 0; 219209ff23fSmrg uint32_t crtc_ext_cntl = INREG(RADEON_CRTC_EXT_CNTL); 220209ff23fSmrg uint32_t fp2_gen_cntl = 0; 221209ff23fSmrg 222209ff23fSmrg if (PCI_DEV_DEVICE_ID(info->PciInfo) == PCI_CHIP_RV100_QY) 223209ff23fSmrg fp2_gen_cntl = INREG(RADEON_FP2_GEN_CNTL); 224209ff23fSmrg 225209ff23fSmrg if (pRADEONEnt->HasCRTC2) 226209ff23fSmrg crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); 227209ff23fSmrg 228209ff23fSmrg OUTREG(RADEON_SEPROM_CNTL1, ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) | 229209ff23fSmrg (0xc << RADEON_SCK_PRESCALE_SHIFT))); 230209ff23fSmrg 231209ff23fSmrg /* disable VIP */ 232209ff23fSmrg OUTREG(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); 233209ff23fSmrg 234209ff23fSmrg /* enable the rom */ 235209ff23fSmrg OUTREG(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); 236209ff23fSmrg 237209ff23fSmrg /* Turn off mem requests and CRTC for both controllers */ 238209ff23fSmrg OUTREG(RADEON_CRTC_GEN_CNTL, ((crtc_gen_cntl & ~RADEON_CRTC_EN) | 239209ff23fSmrg (RADEON_CRTC_DISP_REQ_EN_B | 240209ff23fSmrg RADEON_CRTC_EXT_DISP_EN))); 241209ff23fSmrg if (pRADEONEnt->HasCRTC2) 242209ff23fSmrg OUTREG(RADEON_CRTC2_GEN_CNTL, ((crtc2_gen_cntl & ~RADEON_CRTC2_EN) | 243209ff23fSmrg RADEON_CRTC2_DISP_REQ_EN_B)); 244209ff23fSmrg 245209ff23fSmrg /* Turn off CRTC */ 246209ff23fSmrg OUTREG(RADEON_CRTC_EXT_CNTL, ((crtc_ext_cntl & ~RADEON_CRTC_CRT_ON) | 247209ff23fSmrg (RADEON_CRTC_SYNC_TRISTAT | 248209ff23fSmrg RADEON_CRTC_DISPLAY_DIS))); 249209ff23fSmrg 250209ff23fSmrg if (PCI_DEV_DEVICE_ID(info->PciInfo) == PCI_CHIP_RV100_QY) 251209ff23fSmrg OUTREG(RADEON_FP2_GEN_CNTL, (fp2_gen_cntl & ~RADEON_FP2_ON)); 252209ff23fSmrg 253209ff23fSmrg ret = radeon_read_bios(pScrn); 254209ff23fSmrg 255209ff23fSmrg /* restore regs */ 256209ff23fSmrg OUTREG(RADEON_SEPROM_CNTL1, seprom_cntl1); 257209ff23fSmrg OUTREG(RADEON_VIPH_CONTROL, viph_control); 258209ff23fSmrg OUTREG(RADEON_BUS_CNTL, bus_cntl); 259209ff23fSmrg OUTREG(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); 260209ff23fSmrg if (pRADEONEnt->HasCRTC2) 261209ff23fSmrg OUTREG(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); 262209ff23fSmrg OUTREG(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); 263209ff23fSmrg if (PCI_DEV_DEVICE_ID(info->PciInfo) == PCI_CHIP_RV100_QY) 264209ff23fSmrg OUTREG(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); 265209ff23fSmrg } 266209ff23fSmrg return ret; 267209ff23fSmrg} 268209ff23fSmrg 269209ff23fSmrg/* Read the Video BIOS block and the FP registers (if applicable). */ 270209ff23fSmrgBool 271209ff23fSmrgRADEONGetBIOSInfo(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) 272209ff23fSmrg{ 273209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 274209ff23fSmrg int tmp; 275209ff23fSmrg unsigned short dptr; 276209ff23fSmrg 277209ff23fSmrg#ifdef XSERVER_LIBPCIACCESS 278209ff23fSmrg int size = info->PciInfo->rom_size > RADEON_VBIOS_SIZE ? info->PciInfo->rom_size : RADEON_VBIOS_SIZE; 279209ff23fSmrg info->VBIOS = xalloc(size); 280209ff23fSmrg#else 281209ff23fSmrg info->VBIOS = xalloc(RADEON_VBIOS_SIZE); 282209ff23fSmrg#endif 283209ff23fSmrg if (!info->VBIOS) { 284209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 285209ff23fSmrg "Cannot allocate space for hold Video BIOS!\n"); 286209ff23fSmrg return FALSE; 287209ff23fSmrg } else { 288209ff23fSmrg if (pInt10) { 289209ff23fSmrg info->BIOSAddr = pInt10->BIOSseg << 4; 290209ff23fSmrg (void)memcpy(info->VBIOS, xf86int10Addr(pInt10, info->BIOSAddr), 291209ff23fSmrg RADEON_VBIOS_SIZE); 292209ff23fSmrg } else if (!radeon_read_bios(pScrn)) { 293209ff23fSmrg (void)radeon_read_unposted_bios(pScrn); 294209ff23fSmrg } 295209ff23fSmrg } 296209ff23fSmrg 297209ff23fSmrg if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { 298209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 299209ff23fSmrg "Unrecognized BIOS signature, BIOS data will not be used\n"); 300209ff23fSmrg xfree (info->VBIOS); 301209ff23fSmrg info->VBIOS = NULL; 302209ff23fSmrg return FALSE; 303209ff23fSmrg } 304209ff23fSmrg 305209ff23fSmrg /* Verify it's an x86 BIOS not OF firmware, copied from radeonfb */ 306209ff23fSmrg dptr = RADEON_BIOS16(0x18); 307209ff23fSmrg /* If PCI data signature is wrong assume x86 video BIOS anyway */ 308209ff23fSmrg if (RADEON_BIOS32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) { 309209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 310209ff23fSmrg "ROM PCI data signature incorrect, ignoring\n"); 311209ff23fSmrg } 312209ff23fSmrg else if (info->VBIOS[dptr + 0x14] != 0x0) { 313209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 314209ff23fSmrg "Not an x86 BIOS ROM image, BIOS data will not be used\n"); 315209ff23fSmrg xfree (info->VBIOS); 316209ff23fSmrg info->VBIOS = NULL; 317209ff23fSmrg return FALSE; 318209ff23fSmrg } 319209ff23fSmrg 320209ff23fSmrg if (info->VBIOS) info->ROMHeaderStart = RADEON_BIOS16(0x48); 321209ff23fSmrg 322209ff23fSmrg if(!info->ROMHeaderStart) { 323209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 324209ff23fSmrg "Invalid ROM pointer, BIOS data will not be used\n"); 325209ff23fSmrg xfree (info->VBIOS); 326209ff23fSmrg info->VBIOS = NULL; 327209ff23fSmrg return FALSE; 328209ff23fSmrg } 329209ff23fSmrg 330209ff23fSmrg tmp = info->ROMHeaderStart + 4; 331209ff23fSmrg if ((RADEON_BIOS8(tmp) == 'A' && 332209ff23fSmrg RADEON_BIOS8(tmp+1) == 'T' && 333209ff23fSmrg RADEON_BIOS8(tmp+2) == 'O' && 334209ff23fSmrg RADEON_BIOS8(tmp+3) == 'M') || 335209ff23fSmrg (RADEON_BIOS8(tmp) == 'M' && 336209ff23fSmrg RADEON_BIOS8(tmp+1) == 'O' && 337209ff23fSmrg RADEON_BIOS8(tmp+2) == 'T' && 338209ff23fSmrg RADEON_BIOS8(tmp+3) == 'A')) 339209ff23fSmrg info->IsAtomBios = TRUE; 340209ff23fSmrg else 341209ff23fSmrg info->IsAtomBios = FALSE; 342209ff23fSmrg 343209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s BIOS detected\n", 344209ff23fSmrg info->IsAtomBios ? "ATOM":"Legacy"); 345209ff23fSmrg 346209ff23fSmrg if (info->IsAtomBios) { 347209ff23fSmrg AtomBiosArgRec atomBiosArg; 348209ff23fSmrg 349209ff23fSmrg if (RHDAtomBiosFunc(pScrn->scrnIndex, NULL, ATOMBIOS_INIT, &atomBiosArg) 350209ff23fSmrg == ATOM_SUCCESS) { 351209ff23fSmrg info->atomBIOS = atomBiosArg.atomhandle; 352209ff23fSmrg } 353209ff23fSmrg 354209ff23fSmrg atomBiosArg.fb.start = info->FbFreeStart; 355209ff23fSmrg atomBiosArg.fb.size = info->FbFreeSize; 356209ff23fSmrg if (RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, ATOMBIOS_ALLOCATE_FB_SCRATCH, 357209ff23fSmrg &atomBiosArg) == ATOM_SUCCESS) { 358209ff23fSmrg 359209ff23fSmrg info->FbFreeStart = atomBiosArg.fb.start; 360209ff23fSmrg info->FbFreeSize = atomBiosArg.fb.size; 361209ff23fSmrg } 362209ff23fSmrg 363209ff23fSmrg RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, GET_DEFAULT_ENGINE_CLOCK, 364209ff23fSmrg &atomBiosArg); 365209ff23fSmrg RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, GET_DEFAULT_MEMORY_CLOCK, 366209ff23fSmrg &atomBiosArg); 367209ff23fSmrg RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, 368209ff23fSmrg GET_MAX_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg); 369209ff23fSmrg RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, 370209ff23fSmrg GET_MIN_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg); 371209ff23fSmrg RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, 372209ff23fSmrg GET_MAX_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg); 373209ff23fSmrg RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, 374209ff23fSmrg GET_MIN_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg); 375209ff23fSmrg RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, 376209ff23fSmrg GET_MAX_PIXEL_CLK, &atomBiosArg); 377209ff23fSmrg RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, 378209ff23fSmrg GET_REF_CLOCK, &atomBiosArg); 379209ff23fSmrg 380209ff23fSmrg info->MasterDataStart = RADEON_BIOS16 (info->ROMHeaderStart + 32); 381209ff23fSmrg } 382209ff23fSmrg#if 0 383209ff23fSmrg else { 384209ff23fSmrg /* non-primary card may need posting */ 385209ff23fSmrg if (!pInt10) { 386209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Attempting to POST via BIOS tables\n"); 387209ff23fSmrg RADEONGetBIOSInitTableOffsets(pScrn); 388209ff23fSmrg RADEONPostCardFromBIOSTables(pScrn); 389209ff23fSmrg } 390209ff23fSmrg } 391209ff23fSmrg#endif 392209ff23fSmrg return TRUE; 393209ff23fSmrg} 394209ff23fSmrg 395209ff23fSmrgstatic Bool RADEONGetATOMConnectorInfoFromBIOS (ScrnInfoPtr pScrn) 396209ff23fSmrg{ 397209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 398209ff23fSmrg 399209ff23fSmrg if (!info->VBIOS) return FALSE; 400209ff23fSmrg 401209ff23fSmrg if (RADEONGetATOMConnectorInfoFromBIOSObject(pScrn)) 402209ff23fSmrg return TRUE; 403209ff23fSmrg 404209ff23fSmrg if (RADEONGetATOMConnectorInfoFromBIOSConnectorTable(pScrn)) 405209ff23fSmrg return TRUE; 406209ff23fSmrg 407209ff23fSmrg return FALSE; 408209ff23fSmrg} 409209ff23fSmrg 410209ff23fSmrgstatic void RADEONApplyLegacyQuirks(ScrnInfoPtr pScrn, int index) 411209ff23fSmrg{ 412209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 413209ff23fSmrg 414209ff23fSmrg /* on XPRESS chips, CRT2_DDC and MONID_DCC both use the 415209ff23fSmrg * MONID gpio, but use different pins. 416209ff23fSmrg * CRT2_DDC uses the standard pinout, MONID_DDC uses 417209ff23fSmrg * something else. 418209ff23fSmrg */ 419209ff23fSmrg if ((info->ChipFamily == CHIP_FAMILY_RS400 || 420209ff23fSmrg info->ChipFamily == CHIP_FAMILY_RS480) && 421209ff23fSmrg info->BiosConnector[index].ConnectorType == CONNECTOR_VGA && 422209ff23fSmrg info->BiosConnector[index].ddc_i2c.mask_clk_reg == RADEON_GPIO_CRT2_DDC) { 423209ff23fSmrg info->BiosConnector[index].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID); 424209ff23fSmrg } 425209ff23fSmrg 426209ff23fSmrg /* XPRESS desktop chips seem to have a proprietary connector listed for 427209ff23fSmrg * DVI-D, try and do the right thing here. 428209ff23fSmrg */ 429209ff23fSmrg if ((!info->IsMobility) && 430209ff23fSmrg (info->BiosConnector[index].ConnectorType == CONNECTOR_LVDS)) { 431209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 432209ff23fSmrg "Proprietary connector found, assuming DVI-D\n"); 433209ff23fSmrg info->BiosConnector[index].DACType = DAC_NONE; 434209ff23fSmrg info->BiosConnector[index].TMDSType = TMDS_EXT; 435209ff23fSmrg info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D; 436209ff23fSmrg } 437209ff23fSmrg 438209ff23fSmrg /* Certain IBM chipset RN50s have a BIOS reporting two VGAs, 439209ff23fSmrg one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */ 440209ff23fSmrg if (info->Chipset == PCI_CHIP_RN50_515E && 441209ff23fSmrg PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1014) { 442209ff23fSmrg if (info->BiosConnector[index].ConnectorType == CONNECTOR_VGA && 443209ff23fSmrg info->BiosConnector[index].ddc_i2c.mask_clk_reg == RADEON_GPIO_CRT2_DDC) { 444209ff23fSmrg info->BiosConnector[index].valid = FALSE; 445209ff23fSmrg } 446209ff23fSmrg } 447209ff23fSmrg 448209ff23fSmrg /* Some RV100 cards with 2 VGA ports show up with DVI+VGA */ 449209ff23fSmrg if (info->Chipset == PCI_CHIP_RV100_QY && 450209ff23fSmrg PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1002 && 451209ff23fSmrg PCI_SUB_DEVICE_ID(info->PciInfo) == 0x013a) { 452209ff23fSmrg if (info->BiosConnector[index].ConnectorType == CONNECTOR_DVI_I) { 453209ff23fSmrg info->BiosConnector[index].ConnectorType = CONNECTOR_VGA; 454209ff23fSmrg } 455209ff23fSmrg } 456209ff23fSmrg 457209ff23fSmrg} 458209ff23fSmrg 459209ff23fSmrgstatic Bool RADEONGetLegacyConnectorInfoFromBIOS (ScrnInfoPtr pScrn) 460209ff23fSmrg{ 461209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 462209ff23fSmrg int offset, i, entry, tmp, tmp0, tmp1; 463209ff23fSmrg RADEONLegacyDDCType DDCType; 464209ff23fSmrg RADEONLegacyConnectorType ConnectorType; 465209ff23fSmrg 466209ff23fSmrg if (!info->VBIOS) return FALSE; 467209ff23fSmrg 468209ff23fSmrg offset = RADEON_BIOS16(info->ROMHeaderStart + 0x50); 469209ff23fSmrg if (offset) { 470209ff23fSmrg for (i = 0; i < 4; i++) { 471209ff23fSmrg entry = offset + 2 + i*2; 472209ff23fSmrg 473209ff23fSmrg if (!RADEON_BIOS16(entry)) { 474209ff23fSmrg break; 475209ff23fSmrg } 476209ff23fSmrg info->BiosConnector[i].valid = TRUE; 477209ff23fSmrg tmp = RADEON_BIOS16(entry); 478209ff23fSmrg info->BiosConnector[i].ConnectorType = (tmp >> 12) & 0xf; 479209ff23fSmrg ConnectorType = (tmp >> 12) & 0xf; 480209ff23fSmrg switch (ConnectorType) { 481209ff23fSmrg case CONNECTOR_PROPRIETARY_LEGACY: 482209ff23fSmrg info->BiosConnector[i].ConnectorType = CONNECTOR_LVDS; 483209ff23fSmrg break; 484209ff23fSmrg case CONNECTOR_CRT_LEGACY: 485209ff23fSmrg info->BiosConnector[i].ConnectorType = CONNECTOR_VGA; 486209ff23fSmrg break; 487209ff23fSmrg case CONNECTOR_DVI_I_LEGACY: 488209ff23fSmrg info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_I; 489209ff23fSmrg break; 490209ff23fSmrg case CONNECTOR_DVI_D_LEGACY: 491209ff23fSmrg info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_D; 492209ff23fSmrg break; 493209ff23fSmrg case CONNECTOR_CTV_LEGACY: 494209ff23fSmrg info->BiosConnector[i].ConnectorType = CONNECTOR_CTV; 495209ff23fSmrg break; 496209ff23fSmrg case CONNECTOR_STV_LEGACY: 497209ff23fSmrg info->BiosConnector[i].ConnectorType = CONNECTOR_STV; 498209ff23fSmrg break; 499209ff23fSmrg default: 500209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown Connector Type: %d\n", ConnectorType); 501209ff23fSmrg info->BiosConnector[i].valid = FALSE; 502209ff23fSmrg break; 503209ff23fSmrg } 504209ff23fSmrg 505209ff23fSmrg info->BiosConnector[i].ddc_i2c.valid = FALSE; 506209ff23fSmrg 507209ff23fSmrg DDCType = (tmp >> 8) & 0xf; 508209ff23fSmrg switch (DDCType) { 509209ff23fSmrg case DDC_MONID: 510209ff23fSmrg info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID); 511209ff23fSmrg break; 512209ff23fSmrg case DDC_DVI: 513209ff23fSmrg info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC); 514209ff23fSmrg break; 515209ff23fSmrg case DDC_VGA: 516209ff23fSmrg info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_VGA_DDC); 517209ff23fSmrg break; 518209ff23fSmrg case DDC_CRT2: 519209ff23fSmrg info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); 520209ff23fSmrg break; 521209ff23fSmrg default: 522209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown DDC Type: %d\n", DDCType); 523209ff23fSmrg break; 524209ff23fSmrg } 525209ff23fSmrg 526209ff23fSmrg if (tmp & 0x1) 527209ff23fSmrg info->BiosConnector[i].DACType = DAC_TVDAC; 528209ff23fSmrg else 529209ff23fSmrg info->BiosConnector[i].DACType = DAC_PRIMARY; 530209ff23fSmrg 531209ff23fSmrg /* For RS300/RS350/RS400 chips, there is no primary DAC. Force VGA port to use TVDAC*/ 532209ff23fSmrg if (info->IsIGP) 533209ff23fSmrg info->BiosConnector[i].DACType = DAC_TVDAC; 534209ff23fSmrg 535209ff23fSmrg if ((tmp >> 4) & 0x1) 536209ff23fSmrg info->BiosConnector[i].TMDSType = TMDS_EXT; 537209ff23fSmrg else 538209ff23fSmrg info->BiosConnector[i].TMDSType = TMDS_INT; 539209ff23fSmrg 540209ff23fSmrg RADEONApplyLegacyQuirks(pScrn, i); 541209ff23fSmrg 542209ff23fSmrg } 543209ff23fSmrg } else { 544209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Connector Info Table found!\n"); 545209ff23fSmrg 546209ff23fSmrg /* old radeons and r128 didn't use connector tables you just check 547209ff23fSmrg * for LVDS, DVI, TV, etc. tables 548209ff23fSmrg */ 549209ff23fSmrg offset = RADEON_BIOS16(info->ROMHeaderStart + 0x34); 550209ff23fSmrg if (offset) { 551209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 552209ff23fSmrg "Found DFP table, assuming DVI connector\n"); 553209ff23fSmrg info->BiosConnector[0].valid = TRUE; 554209ff23fSmrg info->BiosConnector[0].ConnectorType = CONNECTOR_DVI_I; 555209ff23fSmrg info->BiosConnector[0].DACType = DAC_PRIMARY; 556209ff23fSmrg info->BiosConnector[0].TMDSType = TMDS_INT; 557209ff23fSmrg info->BiosConnector[0].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC); 558209ff23fSmrg } else 559209ff23fSmrg return FALSE; 560209ff23fSmrg } 561209ff23fSmrg 562209ff23fSmrg /* check LVDS table */ 563209ff23fSmrg if (info->IsMobility) { 564209ff23fSmrg offset = RADEON_BIOS16(info->ROMHeaderStart + 0x40); 565209ff23fSmrg if (offset) { 566209ff23fSmrg info->BiosConnector[4].valid = TRUE; 567209ff23fSmrg info->BiosConnector[4].ConnectorType = CONNECTOR_LVDS; 568209ff23fSmrg info->BiosConnector[4].DACType = DAC_NONE; 569209ff23fSmrg info->BiosConnector[4].TMDSType = TMDS_NONE; 570209ff23fSmrg info->BiosConnector[4].ddc_i2c.valid = FALSE; 571209ff23fSmrg 572209ff23fSmrg tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x42); 573209ff23fSmrg if (tmp) { 574209ff23fSmrg tmp0 = RADEON_BIOS16(tmp + 0x15); 575209ff23fSmrg if (tmp0) { 576209ff23fSmrg tmp1 = RADEON_BIOS8(tmp0+2) & 0x07; 577209ff23fSmrg if (tmp1) { 578209ff23fSmrg DDCType = tmp1; 579209ff23fSmrg switch (DDCType) { 580209ff23fSmrg case DDC_MONID: 581209ff23fSmrg info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID); 582209ff23fSmrg break; 583209ff23fSmrg case DDC_DVI: 584209ff23fSmrg info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC); 585209ff23fSmrg break; 586209ff23fSmrg case DDC_VGA: 587209ff23fSmrg info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_VGA_DDC); 588209ff23fSmrg break; 589209ff23fSmrg case DDC_CRT2: 590209ff23fSmrg info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); 591209ff23fSmrg break; 592209ff23fSmrg case DDC_LCD: 593209ff23fSmrg info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_LCD_GPIO_MASK); 594209ff23fSmrg info->BiosConnector[4].ddc_i2c.mask_clk_mask = 595209ff23fSmrg RADEON_BIOS32(tmp0 + 0x03) | RADEON_BIOS32(tmp0 + 0x07); 596209ff23fSmrg info->BiosConnector[4].ddc_i2c.mask_data_mask = 597209ff23fSmrg RADEON_BIOS32(tmp0 + 0x03) | RADEON_BIOS32(tmp0 + 0x07); 598209ff23fSmrg info->BiosConnector[4].ddc_i2c.put_clk_mask = RADEON_BIOS32(tmp0 + 0x03); 599209ff23fSmrg info->BiosConnector[4].ddc_i2c.put_data_mask = RADEON_BIOS32(tmp0 + 0x07); 600209ff23fSmrg info->BiosConnector[4].ddc_i2c.get_clk_mask = RADEON_BIOS32(tmp0 + 0x03); 601209ff23fSmrg info->BiosConnector[4].ddc_i2c.get_data_mask = RADEON_BIOS32(tmp0 + 0x07); 602209ff23fSmrg break; 603209ff23fSmrg case DDC_GPIO: 604209ff23fSmrg info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_MDGPIO_EN_REG); 605209ff23fSmrg info->BiosConnector[4].ddc_i2c.mask_clk_mask = 606209ff23fSmrg RADEON_BIOS32(tmp0 + 0x03) | RADEON_BIOS32(tmp0 + 0x07); 607209ff23fSmrg info->BiosConnector[4].ddc_i2c.mask_data_mask = 608209ff23fSmrg RADEON_BIOS32(tmp0 + 0x03) | RADEON_BIOS32(tmp0 + 0x07); 609209ff23fSmrg info->BiosConnector[4].ddc_i2c.put_clk_mask = RADEON_BIOS32(tmp0 + 0x03); 610209ff23fSmrg info->BiosConnector[4].ddc_i2c.put_data_mask = RADEON_BIOS32(tmp0 + 0x07); 611209ff23fSmrg info->BiosConnector[4].ddc_i2c.get_clk_mask = RADEON_BIOS32(tmp0 + 0x03); 612209ff23fSmrg info->BiosConnector[4].ddc_i2c.get_data_mask = RADEON_BIOS32(tmp0 + 0x07); 613209ff23fSmrg break; 614209ff23fSmrg default: 615209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown DDC Type: %d\n", DDCType); 616209ff23fSmrg break; 617209ff23fSmrg } 618209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "LCD DDC Info Table found!\n"); 619209ff23fSmrg } 620209ff23fSmrg } 621209ff23fSmrg } else { 622209ff23fSmrg info->BiosConnector[4].ddc_i2c.valid = FALSE; 623209ff23fSmrg } 624209ff23fSmrg } 625209ff23fSmrg } 626209ff23fSmrg 627209ff23fSmrg /* check TV table */ 628209ff23fSmrg if (info->InternalTVOut) { 629209ff23fSmrg offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32); 630209ff23fSmrg if (offset) { 631209ff23fSmrg if (RADEON_BIOS8(offset + 6) == 'T') { 632209ff23fSmrg info->BiosConnector[5].valid = TRUE; 633209ff23fSmrg /* assume s-video for now */ 634209ff23fSmrg info->BiosConnector[5].ConnectorType = CONNECTOR_STV; 635209ff23fSmrg info->BiosConnector[5].DACType = DAC_TVDAC; 636209ff23fSmrg info->BiosConnector[5].TMDSType = TMDS_NONE; 637209ff23fSmrg info->BiosConnector[5].ddc_i2c.valid = FALSE; 638209ff23fSmrg } 639209ff23fSmrg } 640209ff23fSmrg } 641209ff23fSmrg 642209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bios Connector table: \n"); 643209ff23fSmrg for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) { 644209ff23fSmrg if (info->BiosConnector[i].valid) { 645209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Port%d: DDCType-0x%x, DACType-%d, TMDSType-%d, ConnectorType-%d\n", 646209ff23fSmrg i, (unsigned int)info->BiosConnector[i].ddc_i2c.mask_clk_reg, info->BiosConnector[i].DACType, 647209ff23fSmrg info->BiosConnector[i].TMDSType, info->BiosConnector[i].ConnectorType); 648209ff23fSmrg } 649209ff23fSmrg } 650209ff23fSmrg 651209ff23fSmrg return TRUE; 652209ff23fSmrg} 653209ff23fSmrg 654209ff23fSmrgBool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn) 655209ff23fSmrg{ 656209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 657209ff23fSmrg 658209ff23fSmrg if(!info->VBIOS) return FALSE; 659209ff23fSmrg 660209ff23fSmrg if (info->IsAtomBios) 661209ff23fSmrg return RADEONGetATOMConnectorInfoFromBIOS(pScrn); 662209ff23fSmrg else 663209ff23fSmrg return RADEONGetLegacyConnectorInfoFromBIOS(pScrn); 664209ff23fSmrg} 665209ff23fSmrg 666209ff23fSmrgBool RADEONGetTVInfoFromBIOS (xf86OutputPtr output) { 667209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 668209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 669209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 670209ff23fSmrg int offset, refclk, stds; 671209ff23fSmrg 672209ff23fSmrg if (!info->VBIOS) return FALSE; 673209ff23fSmrg 674209ff23fSmrg if (info->IsAtomBios) { 675209ff23fSmrg return RADEONGetATOMTVInfo(output); 676209ff23fSmrg } else { 677209ff23fSmrg offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32); 678209ff23fSmrg if (offset) { 679209ff23fSmrg if (RADEON_BIOS8(offset + 6) == 'T') { 680209ff23fSmrg switch (RADEON_BIOS8(offset + 7) & 0xf) { 681209ff23fSmrg case 1: 682209ff23fSmrg radeon_output->default_tvStd = TV_STD_NTSC; 683209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC\n"); 684209ff23fSmrg break; 685209ff23fSmrg case 2: 686209ff23fSmrg radeon_output->default_tvStd = TV_STD_PAL; 687209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL\n"); 688209ff23fSmrg break; 689209ff23fSmrg case 3: 690209ff23fSmrg radeon_output->default_tvStd = TV_STD_PAL_M; 691209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-M\n"); 692209ff23fSmrg break; 693209ff23fSmrg case 4: 694209ff23fSmrg radeon_output->default_tvStd = TV_STD_PAL_60; 695209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-60\n"); 696209ff23fSmrg break; 697209ff23fSmrg case 5: 698209ff23fSmrg radeon_output->default_tvStd = TV_STD_NTSC_J; 699209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC-J\n"); 700209ff23fSmrg break; 701209ff23fSmrg case 6: 702209ff23fSmrg radeon_output->default_tvStd = TV_STD_SCART_PAL; 703209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: SCART-PAL\n"); 704209ff23fSmrg break; 705209ff23fSmrg default: 706209ff23fSmrg radeon_output->default_tvStd = TV_STD_NTSC; 707209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Unknown TV standard; defaulting to NTSC\n"); 708209ff23fSmrg break; 709209ff23fSmrg } 710209ff23fSmrg radeon_output->tvStd = radeon_output->default_tvStd; 711209ff23fSmrg 712209ff23fSmrg refclk = (RADEON_BIOS8(offset + 9) >> 2) & 0x3; 713209ff23fSmrg if (refclk == 0) 714209ff23fSmrg radeon_output->TVRefClk = 29.498928713; /* MHz */ 715209ff23fSmrg else if (refclk == 1) 716209ff23fSmrg radeon_output->TVRefClk = 28.636360000; 717209ff23fSmrg else if (refclk == 2) 718209ff23fSmrg radeon_output->TVRefClk = 14.318180000; 719209ff23fSmrg else if (refclk == 3) 720209ff23fSmrg radeon_output->TVRefClk = 27.000000000; 721209ff23fSmrg 722209ff23fSmrg radeon_output->SupportedTVStds = radeon_output->default_tvStd; 723209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standards supported by chip: "); 724209ff23fSmrg stds = RADEON_BIOS8(offset + 10) & 0x1f; 725209ff23fSmrg if (stds & TV_STD_NTSC) { 726209ff23fSmrg radeon_output->SupportedTVStds |= TV_STD_NTSC; 727209ff23fSmrg ErrorF("NTSC "); 728209ff23fSmrg } 729209ff23fSmrg if (stds & TV_STD_PAL) { 730209ff23fSmrg radeon_output->SupportedTVStds |= TV_STD_PAL; 731209ff23fSmrg ErrorF("PAL "); 732209ff23fSmrg } 733209ff23fSmrg if (stds & TV_STD_PAL_M) { 734209ff23fSmrg radeon_output->SupportedTVStds |= TV_STD_PAL_M; 735209ff23fSmrg ErrorF("PAL-M "); 736209ff23fSmrg } 737209ff23fSmrg if (stds & TV_STD_PAL_60) { 738209ff23fSmrg radeon_output->SupportedTVStds |= TV_STD_PAL_60; 739209ff23fSmrg ErrorF("PAL-60 "); 740209ff23fSmrg } 741209ff23fSmrg if (stds & TV_STD_NTSC_J) { 742209ff23fSmrg radeon_output->SupportedTVStds |= TV_STD_NTSC_J; 743209ff23fSmrg ErrorF("NTSC-J "); 744209ff23fSmrg } 745209ff23fSmrg if (stds & TV_STD_SCART_PAL) { 746209ff23fSmrg radeon_output->SupportedTVStds |= TV_STD_SCART_PAL; 747209ff23fSmrg ErrorF("SCART-PAL"); 748209ff23fSmrg } 749209ff23fSmrg ErrorF("\n"); 750209ff23fSmrg 751209ff23fSmrg return TRUE; 752209ff23fSmrg } 753209ff23fSmrg } 754209ff23fSmrg } 755209ff23fSmrg return FALSE; 756209ff23fSmrg} 757209ff23fSmrg 758209ff23fSmrg/* Read PLL parameters from BIOS block. Default to typical values if there 759209ff23fSmrg is no BIOS. */ 760209ff23fSmrgBool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn) 761209ff23fSmrg{ 762209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 763209ff23fSmrg RADEONPLLPtr pll = &info->pll; 764209ff23fSmrg uint16_t pll_info_block; 765209ff23fSmrg 766209ff23fSmrg if (!info->VBIOS) { 767209ff23fSmrg return FALSE; 768209ff23fSmrg } else { 769209ff23fSmrg if (info->IsAtomBios) { 770209ff23fSmrg pll_info_block = RADEON_BIOS16 (info->MasterDataStart + 12); 771209ff23fSmrg 772209ff23fSmrg pll->reference_freq = RADEON_BIOS16 (pll_info_block + 82); 773209ff23fSmrg pll->reference_div = 0; /* Need to derive from existing setting 774209ff23fSmrg or use a new algorithm to calculate 775209ff23fSmrg from min_input and max_input 776209ff23fSmrg */ 777209ff23fSmrg pll->pll_out_min = RADEON_BIOS16 (pll_info_block + 78); 778209ff23fSmrg pll->pll_out_max = RADEON_BIOS32 (pll_info_block + 32); 779209ff23fSmrg 780209ff23fSmrg if (pll->pll_out_min == 0) { 781209ff23fSmrg if (IS_AVIVO_VARIANT) 782209ff23fSmrg pll->pll_out_min = 64800; 783209ff23fSmrg else 784209ff23fSmrg pll->pll_out_min = 20000; 785209ff23fSmrg } 786209ff23fSmrg 787209ff23fSmrg pll->pll_in_min = RADEON_BIOS16 (pll_info_block + 74); 788209ff23fSmrg pll->pll_in_max = RADEON_BIOS16 (pll_info_block + 76); 789209ff23fSmrg 790209ff23fSmrg pll->xclk = RADEON_BIOS16 (pll_info_block + 72); 791209ff23fSmrg 792209ff23fSmrg info->sclk = RADEON_BIOS32(pll_info_block + 8) / 100.0; 793209ff23fSmrg info->mclk = RADEON_BIOS32(pll_info_block + 12) / 100.0; 794209ff23fSmrg } else { 795209ff23fSmrg int rev; 796209ff23fSmrg 797209ff23fSmrg pll_info_block = RADEON_BIOS16 (info->ROMHeaderStart + 0x30); 798209ff23fSmrg 799209ff23fSmrg rev = RADEON_BIOS8(pll_info_block); 800209ff23fSmrg 801209ff23fSmrg pll->reference_freq = RADEON_BIOS16 (pll_info_block + 0x0e); 802209ff23fSmrg pll->reference_div = RADEON_BIOS16 (pll_info_block + 0x10); 803209ff23fSmrg pll->pll_out_min = RADEON_BIOS32 (pll_info_block + 0x12); 804209ff23fSmrg pll->pll_out_max = RADEON_BIOS32 (pll_info_block + 0x16); 805209ff23fSmrg 806209ff23fSmrg if (rev > 9) { 807209ff23fSmrg pll->pll_in_min = RADEON_BIOS32(pll_info_block + 0x36); 808209ff23fSmrg pll->pll_in_max = RADEON_BIOS32(pll_info_block + 0x3a); 809209ff23fSmrg } else { 810209ff23fSmrg pll->pll_in_min = 40; 811209ff23fSmrg pll->pll_in_max = 500; 812209ff23fSmrg } 813209ff23fSmrg 814209ff23fSmrg pll->xclk = RADEON_BIOS16(pll_info_block + 0x08); 815209ff23fSmrg 816209ff23fSmrg info->sclk = RADEON_BIOS16(pll_info_block + 8) / 100.0; 817209ff23fSmrg info->mclk = RADEON_BIOS16(pll_info_block + 10) / 100.0; 818209ff23fSmrg } 819209ff23fSmrg 820209ff23fSmrg if (info->sclk == 0) info->sclk = 200; 821209ff23fSmrg if (info->mclk == 0) info->mclk = 200; 822209ff23fSmrg } 823209ff23fSmrg 824209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ref_freq: %d, min_out_pll: %u, " 825209ff23fSmrg "max_out_pll: %u, min_in_pll: %u, max_in_pll: %u, xclk: %d, " 826209ff23fSmrg "sclk: %f, mclk: %f\n", 827209ff23fSmrg pll->reference_freq, (unsigned)pll->pll_out_min, 828209ff23fSmrg (unsigned)pll->pll_out_max, (unsigned)pll->pll_in_min, 829209ff23fSmrg (unsigned)pll->pll_in_max, pll->xclk, info->sclk, info->mclk); 830209ff23fSmrg 831209ff23fSmrg return TRUE; 832209ff23fSmrg} 833209ff23fSmrg 834209ff23fSmrgBool RADEONGetDAC2InfoFromBIOS (xf86OutputPtr output) 835209ff23fSmrg{ 836209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 837209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 838209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 839209ff23fSmrg int offset, rev, bg, dac; 840209ff23fSmrg 841209ff23fSmrg if (!info->VBIOS) return FALSE; 842209ff23fSmrg 843209ff23fSmrg if (xf86ReturnOptValBool(info->Options, OPTION_DEFAULT_TVDAC_ADJ, FALSE)) 844209ff23fSmrg return FALSE; 845209ff23fSmrg 846209ff23fSmrg if (info->IsAtomBios) { 847209ff23fSmrg /* not implemented yet */ 848209ff23fSmrg return FALSE; 849209ff23fSmrg } else { 850209ff23fSmrg /* first check TV table */ 851209ff23fSmrg offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32); 852209ff23fSmrg if (offset) { 853209ff23fSmrg rev = RADEON_BIOS8(offset + 0x3); 854209ff23fSmrg if (rev > 4) { 855209ff23fSmrg bg = RADEON_BIOS8(offset + 0xc) & 0xf; 856209ff23fSmrg dac = RADEON_BIOS8(offset + 0xd) & 0xf; 857209ff23fSmrg radeon_output->ps2_tvdac_adj = (bg << 16) | (dac << 20); 858209ff23fSmrg 859209ff23fSmrg bg = RADEON_BIOS8(offset + 0xe) & 0xf; 860209ff23fSmrg dac = RADEON_BIOS8(offset + 0xf) & 0xf; 861209ff23fSmrg radeon_output->pal_tvdac_adj = (bg << 16) | (dac << 20); 862209ff23fSmrg 863209ff23fSmrg bg = RADEON_BIOS8(offset + 0x10) & 0xf; 864209ff23fSmrg dac = RADEON_BIOS8(offset + 0x11) & 0xf; 865209ff23fSmrg radeon_output->ntsc_tvdac_adj = (bg << 16) | (dac << 20); 866209ff23fSmrg 867209ff23fSmrg return TRUE; 868209ff23fSmrg } else if (rev > 1) { 869209ff23fSmrg bg = RADEON_BIOS8(offset + 0xc) & 0xf; 870209ff23fSmrg dac = (RADEON_BIOS8(offset + 0xc) >> 4) & 0xf; 871209ff23fSmrg radeon_output->ps2_tvdac_adj = (bg << 16) | (dac << 20); 872209ff23fSmrg 873209ff23fSmrg bg = RADEON_BIOS8(offset + 0xd) & 0xf; 874209ff23fSmrg dac = (RADEON_BIOS8(offset + 0xd) >> 4) & 0xf; 875209ff23fSmrg radeon_output->pal_tvdac_adj = (bg << 16) | (dac << 20); 876209ff23fSmrg 877209ff23fSmrg bg = RADEON_BIOS8(offset + 0xe) & 0xf; 878209ff23fSmrg dac = (RADEON_BIOS8(offset + 0xe) >> 4) & 0xf; 879209ff23fSmrg radeon_output->ntsc_tvdac_adj = (bg << 16) | (dac << 20); 880209ff23fSmrg 881209ff23fSmrg return TRUE; 882209ff23fSmrg } 883209ff23fSmrg } 884209ff23fSmrg /* then check CRT table */ 885209ff23fSmrg offset = RADEON_BIOS16(info->ROMHeaderStart + 0x60); 886209ff23fSmrg if (offset) { 887209ff23fSmrg rev = RADEON_BIOS8(offset) & 0x3; 888209ff23fSmrg if (rev < 2) { 889209ff23fSmrg bg = RADEON_BIOS8(offset + 0x3) & 0xf; 890209ff23fSmrg dac = (RADEON_BIOS8(offset + 0x3) >> 4) & 0xf; 891209ff23fSmrg radeon_output->ps2_tvdac_adj = (bg << 16) | (dac << 20); 892209ff23fSmrg radeon_output->pal_tvdac_adj = radeon_output->ps2_tvdac_adj; 893209ff23fSmrg radeon_output->ntsc_tvdac_adj = radeon_output->ps2_tvdac_adj; 894209ff23fSmrg 895209ff23fSmrg return TRUE; 896209ff23fSmrg } else { 897209ff23fSmrg bg = RADEON_BIOS8(offset + 0x4) & 0xf; 898209ff23fSmrg dac = RADEON_BIOS8(offset + 0x5) & 0xf; 899209ff23fSmrg radeon_output->ps2_tvdac_adj = (bg << 16) | (dac << 20); 900209ff23fSmrg radeon_output->pal_tvdac_adj = radeon_output->ps2_tvdac_adj; 901209ff23fSmrg radeon_output->ntsc_tvdac_adj = radeon_output->ps2_tvdac_adj; 902209ff23fSmrg 903209ff23fSmrg return TRUE; 904209ff23fSmrg } 905209ff23fSmrg } 906209ff23fSmrg } 907209ff23fSmrg 908209ff23fSmrg return FALSE; 909209ff23fSmrg} 910209ff23fSmrg 911209ff23fSmrgBool RADEONGetLVDSInfoFromBIOS (xf86OutputPtr output) 912209ff23fSmrg{ 913209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 914209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 915209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 916209ff23fSmrg unsigned long tmp, i; 917209ff23fSmrg 918209ff23fSmrg if (!info->VBIOS) return FALSE; 919209ff23fSmrg 920209ff23fSmrg if (info->IsAtomBios) { 921209ff23fSmrg if((tmp = RADEON_BIOS16 (info->MasterDataStart + 16))) { 922209ff23fSmrg 923209ff23fSmrg radeon_output->PanelXRes = RADEON_BIOS16(tmp+6); 924209ff23fSmrg radeon_output->PanelYRes = RADEON_BIOS16(tmp+10); 925209ff23fSmrg radeon_output->DotClock = RADEON_BIOS16(tmp+4)*10; 926209ff23fSmrg radeon_output->HBlank = RADEON_BIOS16(tmp+8); 927209ff23fSmrg radeon_output->HOverPlus = RADEON_BIOS16(tmp+14); 928209ff23fSmrg radeon_output->HSyncWidth = RADEON_BIOS16(tmp+16); 929209ff23fSmrg radeon_output->VBlank = RADEON_BIOS16(tmp+12); 930209ff23fSmrg radeon_output->VOverPlus = RADEON_BIOS16(tmp+18); 931209ff23fSmrg radeon_output->VSyncWidth = RADEON_BIOS16(tmp+20); 932209ff23fSmrg radeon_output->PanelPwrDly = RADEON_BIOS16(tmp+40); 933209ff23fSmrg 934209ff23fSmrg if (radeon_output->PanelPwrDly > 2000 || radeon_output->PanelPwrDly < 0) 935209ff23fSmrg radeon_output->PanelPwrDly = 2000; 936209ff23fSmrg 937209ff23fSmrg radeon_output->Flags = 0; 938209ff23fSmrg } else { 939209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 940209ff23fSmrg "No LVDS Info Table found in BIOS!\n"); 941209ff23fSmrg return FALSE; 942209ff23fSmrg } 943209ff23fSmrg } else { 944209ff23fSmrg 945209ff23fSmrg tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x40); 946209ff23fSmrg 947209ff23fSmrg if (!tmp) { 948209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 949209ff23fSmrg "No Panel Info Table found in BIOS!\n"); 950209ff23fSmrg return FALSE; 951209ff23fSmrg } else { 952209ff23fSmrg char stmp[30]; 953209ff23fSmrg int tmp0; 954209ff23fSmrg 955209ff23fSmrg for (i = 0; i < 24; i++) 956209ff23fSmrg stmp[i] = RADEON_BIOS8(tmp+i+1); 957209ff23fSmrg stmp[24] = 0; 958209ff23fSmrg 959209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 960209ff23fSmrg "Panel ID string: %s\n", stmp); 961209ff23fSmrg 962209ff23fSmrg radeon_output->PanelXRes = RADEON_BIOS16(tmp+25); 963209ff23fSmrg radeon_output->PanelYRes = RADEON_BIOS16(tmp+27); 964209ff23fSmrg xf86DrvMsg(0, X_INFO, "Panel Size from BIOS: %dx%d\n", 965209ff23fSmrg radeon_output->PanelXRes, radeon_output->PanelYRes); 966209ff23fSmrg 967209ff23fSmrg radeon_output->PanelPwrDly = RADEON_BIOS16(tmp+44); 968209ff23fSmrg if (radeon_output->PanelPwrDly > 2000 || radeon_output->PanelPwrDly < 0) 969209ff23fSmrg radeon_output->PanelPwrDly = 2000; 970209ff23fSmrg 971209ff23fSmrg /* some panels only work well with certain divider combinations. 972209ff23fSmrg */ 973209ff23fSmrg info->RefDivider = RADEON_BIOS16(tmp+46); 974209ff23fSmrg info->PostDivider = RADEON_BIOS8(tmp+48); 975209ff23fSmrg info->FeedbackDivider = RADEON_BIOS16(tmp+49); 976209ff23fSmrg if ((info->RefDivider != 0) && 977209ff23fSmrg (info->FeedbackDivider > 3)) { 978209ff23fSmrg info->UseBiosDividers = TRUE; 979209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 980209ff23fSmrg "BIOS provided dividers will be used.\n"); 981209ff23fSmrg } 982209ff23fSmrg 983209ff23fSmrg /* We don't use a while loop here just in case we have a corrupted BIOS image. 984209ff23fSmrg The max number of table entries is 23 at present, but may grow in future. 985209ff23fSmrg To ensure it works with future revisions we loop it to 32. 986209ff23fSmrg */ 987209ff23fSmrg for (i = 0; i < 32; i++) { 988209ff23fSmrg tmp0 = RADEON_BIOS16(tmp+64+i*2); 989209ff23fSmrg if (tmp0 == 0) break; 990209ff23fSmrg if ((RADEON_BIOS16(tmp0) == radeon_output->PanelXRes) && 991209ff23fSmrg (RADEON_BIOS16(tmp0+2) == radeon_output->PanelYRes)) { 992209ff23fSmrg radeon_output->HBlank = (RADEON_BIOS16(tmp0+17) - 993209ff23fSmrg RADEON_BIOS16(tmp0+19)) * 8; 994209ff23fSmrg radeon_output->HOverPlus = (RADEON_BIOS16(tmp0+21) - 995209ff23fSmrg RADEON_BIOS16(tmp0+19) - 1) * 8; 996209ff23fSmrg radeon_output->HSyncWidth = RADEON_BIOS8(tmp0+23) * 8; 997209ff23fSmrg radeon_output->VBlank = (RADEON_BIOS16(tmp0+24) - 998209ff23fSmrg RADEON_BIOS16(tmp0+26)); 999209ff23fSmrg radeon_output->VOverPlus = ((RADEON_BIOS16(tmp0+28) & 0x7ff) - 1000209ff23fSmrg RADEON_BIOS16(tmp0+26)); 1001209ff23fSmrg radeon_output->VSyncWidth = ((RADEON_BIOS16(tmp0+28) & 0xf800) >> 11); 1002209ff23fSmrg radeon_output->DotClock = RADEON_BIOS16(tmp0+9) * 10; 1003209ff23fSmrg radeon_output->Flags = 0; 1004209ff23fSmrg } 1005209ff23fSmrg } 1006209ff23fSmrg } 1007209ff23fSmrg } 1008209ff23fSmrg 1009209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1010209ff23fSmrg "LVDS Info:\n" 1011209ff23fSmrg "XRes: %d, YRes: %d, DotClock: %d\n" 1012209ff23fSmrg "HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n" 1013209ff23fSmrg "VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n", 1014209ff23fSmrg radeon_output->PanelXRes, radeon_output->PanelYRes, radeon_output->DotClock, 1015209ff23fSmrg radeon_output->HBlank, radeon_output->HOverPlus, radeon_output->HSyncWidth, 1016209ff23fSmrg radeon_output->VBlank, radeon_output->VOverPlus, radeon_output->VSyncWidth); 1017209ff23fSmrg 1018209ff23fSmrg return TRUE; 1019209ff23fSmrg} 1020209ff23fSmrg 1021209ff23fSmrgBool RADEONGetHardCodedEDIDFromBIOS (xf86OutputPtr output) 1022209ff23fSmrg{ 1023209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 1024209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 1025209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1026209ff23fSmrg unsigned long tmp; 1027209ff23fSmrg char EDID[256]; 1028209ff23fSmrg 1029209ff23fSmrg if (!info->VBIOS) return FALSE; 1030209ff23fSmrg 1031209ff23fSmrg if (info->IsAtomBios) { 1032209ff23fSmrg /* Not yet */ 1033209ff23fSmrg return FALSE; 1034209ff23fSmrg } else { 1035209ff23fSmrg if (!(tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x4c))) { 1036209ff23fSmrg return FALSE; 1037209ff23fSmrg } 1038209ff23fSmrg 1039209ff23fSmrg memcpy(EDID, (char*)(info->VBIOS + tmp), 256); 1040209ff23fSmrg 1041209ff23fSmrg radeon_output->DotClock = (*(uint16_t*)(EDID+54)) * 10; 1042209ff23fSmrg radeon_output->PanelXRes = (*(uint8_t*)(EDID+56)) + ((*(uint8_t*)(EDID+58))>>4)*256; 1043209ff23fSmrg radeon_output->HBlank = (*(uint8_t*)(EDID+57)) + ((*(uint8_t*)(EDID+58)) & 0xf)*256; 1044209ff23fSmrg radeon_output->HOverPlus = (*(uint8_t*)(EDID+62)) + ((*(uint8_t*)(EDID+65)>>6)*256); 1045209ff23fSmrg radeon_output->HSyncWidth = (*(uint8_t*)(EDID+63)) + (((*(uint8_t*)(EDID+65)>>4) & 3)*256); 1046209ff23fSmrg radeon_output->PanelYRes = (*(uint8_t*)(EDID+59)) + ((*(uint8_t*)(EDID+61))>>4)*256; 1047209ff23fSmrg radeon_output->VBlank = ((*(uint8_t*)(EDID+60)) + ((*(uint8_t*)(EDID+61)) & 0xf)*256); 1048209ff23fSmrg radeon_output->VOverPlus = (((*(uint8_t*)(EDID+64))>>4) + (((*(uint8_t*)(EDID+65)>>2) & 3)*16)); 1049209ff23fSmrg radeon_output->VSyncWidth = (((*(uint8_t*)(EDID+64)) & 0xf) + ((*(uint8_t*)(EDID+65)) & 3)*256); 1050209ff23fSmrg radeon_output->Flags = V_NHSYNC | V_NVSYNC; /**(uint8_t*)(EDID+71);*/ 1051209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Hardcoded EDID data will be used for TMDS panel\n"); 1052209ff23fSmrg } 1053209ff23fSmrg return TRUE; 1054209ff23fSmrg} 1055209ff23fSmrg 1056209ff23fSmrgBool RADEONGetTMDSInfoFromBIOS (xf86OutputPtr output) 1057209ff23fSmrg{ 1058209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 1059209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 1060209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1061209ff23fSmrg uint32_t tmp, maxfreq; 1062209ff23fSmrg int i, n; 1063209ff23fSmrg 1064209ff23fSmrg if (!info->VBIOS) return FALSE; 1065209ff23fSmrg 1066209ff23fSmrg if (info->IsAtomBios) { 1067209ff23fSmrg if((tmp = RADEON_BIOS16 (info->MasterDataStart + 18))) { 1068209ff23fSmrg 1069209ff23fSmrg maxfreq = RADEON_BIOS16(tmp+4); 1070209ff23fSmrg 1071209ff23fSmrg for (i=0; i<4; i++) { 1072209ff23fSmrg radeon_output->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*6+6); 1073209ff23fSmrg /* This assumes each field in TMDS_PLL has 6 bit as in R300/R420 */ 1074209ff23fSmrg radeon_output->tmds_pll[i].value = ((RADEON_BIOS8(tmp+i*6+8) & 0x3f) | 1075209ff23fSmrg ((RADEON_BIOS8(tmp+i*6+10) & 0x3f)<<6) | 1076209ff23fSmrg ((RADEON_BIOS8(tmp+i*6+9) & 0xf)<<12) | 1077209ff23fSmrg ((RADEON_BIOS8(tmp+i*6+11) & 0xf)<<16)); 1078209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1079209ff23fSmrg "TMDS PLL from BIOS: %u %x\n", 1080209ff23fSmrg (unsigned)radeon_output->tmds_pll[i].freq, 1081209ff23fSmrg (unsigned)radeon_output->tmds_pll[i].value); 1082209ff23fSmrg 1083209ff23fSmrg if (maxfreq == radeon_output->tmds_pll[i].freq) { 1084209ff23fSmrg radeon_output->tmds_pll[i].freq = 0xffffffff; 1085209ff23fSmrg break; 1086209ff23fSmrg } 1087209ff23fSmrg } 1088209ff23fSmrg return TRUE; 1089209ff23fSmrg } 1090209ff23fSmrg } else { 1091209ff23fSmrg 1092209ff23fSmrg tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x34); 1093209ff23fSmrg if (tmp) { 1094209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1095209ff23fSmrg "DFP table revision: %d\n", RADEON_BIOS8(tmp)); 1096209ff23fSmrg if (RADEON_BIOS8(tmp) == 3) { 1097209ff23fSmrg n = RADEON_BIOS8(tmp + 5) + 1; 1098209ff23fSmrg if (n > 4) n = 4; 1099209ff23fSmrg for (i=0; i<n; i++) { 1100209ff23fSmrg radeon_output->tmds_pll[i].value = RADEON_BIOS32(tmp+i*10+0x08); 1101209ff23fSmrg radeon_output->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*10+0x10); 1102209ff23fSmrg } 1103209ff23fSmrg return TRUE; 1104209ff23fSmrg } else if (RADEON_BIOS8(tmp) == 4) { 1105209ff23fSmrg int stride = 0; 1106209ff23fSmrg n = RADEON_BIOS8(tmp + 5) + 1; 1107209ff23fSmrg if (n > 4) n = 4; 1108209ff23fSmrg for (i=0; i<n; i++) { 1109209ff23fSmrg radeon_output->tmds_pll[i].value = RADEON_BIOS32(tmp+stride+0x08); 1110209ff23fSmrg radeon_output->tmds_pll[i].freq = RADEON_BIOS16(tmp+stride+0x10); 1111209ff23fSmrg if (i == 0) stride += 10; 1112209ff23fSmrg else stride += 6; 1113209ff23fSmrg } 1114209ff23fSmrg return TRUE; 1115209ff23fSmrg } 1116209ff23fSmrg } 1117209ff23fSmrg } 1118209ff23fSmrg return FALSE; 1119209ff23fSmrg} 1120209ff23fSmrg 1121209ff23fSmrgBool RADEONGetExtTMDSInfoFromBIOS (xf86OutputPtr output) 1122209ff23fSmrg{ 1123209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 1124209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 1125209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1126209ff23fSmrg int offset, table_start, max_freq, gpio_reg, flags; 1127209ff23fSmrg 1128209ff23fSmrg if (!info->VBIOS) return FALSE; 1129209ff23fSmrg 1130209ff23fSmrg if (info->IsAtomBios) { 1131209ff23fSmrg return FALSE; 1132209ff23fSmrg } else { 1133209ff23fSmrg offset = RADEON_BIOS16(info->ROMHeaderStart + 0x58); 1134209ff23fSmrg if (offset) { 1135209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1136209ff23fSmrg "External TMDS Table revision: %d\n", 1137209ff23fSmrg RADEON_BIOS8(offset)); 1138209ff23fSmrg table_start = offset+4; 1139209ff23fSmrg max_freq = RADEON_BIOS16(table_start); 1140209ff23fSmrg radeon_output->dvo_i2c_slave_addr = RADEON_BIOS8(table_start+2); 1141209ff23fSmrg radeon_output->dvo_i2c.valid = FALSE; 1142209ff23fSmrg gpio_reg = RADEON_BIOS8(table_start+3); 1143209ff23fSmrg if (gpio_reg == 1) 1144209ff23fSmrg radeon_output->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID); 1145209ff23fSmrg else if (gpio_reg == 2) 1146209ff23fSmrg radeon_output->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC); 1147209ff23fSmrg else if (gpio_reg == 3) 1148209ff23fSmrg radeon_output->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_VGA_DDC); 1149209ff23fSmrg else if (gpio_reg == 4) 1150209ff23fSmrg radeon_output->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); 1151209ff23fSmrg else if (gpio_reg == 5) 1152209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1153209ff23fSmrg "unsupported MM gpio_reg\n"); 1154209ff23fSmrg else { 1155209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1156209ff23fSmrg "Unknown gpio reg: %d\n", gpio_reg); 1157209ff23fSmrg return FALSE; 1158209ff23fSmrg } 1159209ff23fSmrg flags = RADEON_BIOS8(table_start+5); 1160209ff23fSmrg radeon_output->dvo_duallink = flags & 0x01; 1161209ff23fSmrg if (radeon_output->dvo_duallink) { 1162209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1163209ff23fSmrg "Duallink TMDS detected\n"); 1164209ff23fSmrg } 1165209ff23fSmrg return TRUE; 1166209ff23fSmrg } 1167209ff23fSmrg } 1168209ff23fSmrg 1169209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1170209ff23fSmrg "No External TMDS Table found\n"); 1171209ff23fSmrg 1172209ff23fSmrg return FALSE; 1173209ff23fSmrg} 1174209ff23fSmrg 1175209ff23fSmrgBool RADEONInitExtTMDSInfoFromBIOS (xf86OutputPtr output) 1176209ff23fSmrg{ 1177209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 1178209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 1179209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 1180209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1181209ff23fSmrg int offset, index, id; 1182209ff23fSmrg uint32_t val, reg, andmask, ormask; 1183209ff23fSmrg 1184209ff23fSmrg if (!info->VBIOS) return FALSE; 1185209ff23fSmrg 1186209ff23fSmrg if (info->IsAtomBios) { 1187209ff23fSmrg return FALSE; 1188209ff23fSmrg } else { 1189209ff23fSmrg offset = RADEON_BIOS16(info->ROMHeaderStart + 0x58); 1190209ff23fSmrg if (offset) { 1191209ff23fSmrg index = offset+10; 1192209ff23fSmrg id = RADEON_BIOS16(index); 1193209ff23fSmrg while (id != 0xffff) { 1194209ff23fSmrg index += 2; 1195209ff23fSmrg switch(id >> 13) { 1196209ff23fSmrg case 0: 1197209ff23fSmrg reg = id & 0x1fff; 1198209ff23fSmrg val = RADEON_BIOS32(index); 1199209ff23fSmrg index += 4; 1200209ff23fSmrg ErrorF("WRITE INDEXED: 0x%x 0x%x\n", 1201209ff23fSmrg (unsigned)reg, (unsigned)val); 1202209ff23fSmrg /*OUTREG(reg, val);*/ 1203209ff23fSmrg break; 1204209ff23fSmrg case 2: 1205209ff23fSmrg reg = id & 0x1fff; 1206209ff23fSmrg andmask = RADEON_BIOS32(index); 1207209ff23fSmrg index += 4; 1208209ff23fSmrg ormask = RADEON_BIOS32(index); 1209209ff23fSmrg index += 4; 1210209ff23fSmrg val = INREG(reg); 1211209ff23fSmrg val = (val & andmask) | ormask; 1212209ff23fSmrg ErrorF("MASK DIRECT: 0x%x 0x%x 0x%x\n", 1213209ff23fSmrg (unsigned)reg, (unsigned)andmask, (unsigned)ormask); 1214209ff23fSmrg /*OUTREG(reg, val);*/ 1215209ff23fSmrg break; 1216209ff23fSmrg case 4: 1217209ff23fSmrg val = RADEON_BIOS16(index); 1218209ff23fSmrg index += 2; 1219209ff23fSmrg ErrorF("delay: %u\n", (unsigned)val); 1220209ff23fSmrg usleep(val); 1221209ff23fSmrg break; 1222209ff23fSmrg case 5: 1223209ff23fSmrg reg = id & 0x1fff; 1224209ff23fSmrg andmask = RADEON_BIOS32(index); 1225209ff23fSmrg index += 4; 1226209ff23fSmrg ormask = RADEON_BIOS32(index); 1227209ff23fSmrg index += 4; 1228209ff23fSmrg ErrorF("MASK PLL: 0x%x 0x%x 0x%x\n", 1229209ff23fSmrg (unsigned)reg, (unsigned)andmask, (unsigned)ormask); 1230209ff23fSmrg /*val = INPLL(pScrn, reg); 1231209ff23fSmrg val = (val & andmask) | ormask; 1232209ff23fSmrg OUTPLL(pScrn, reg, val);*/ 1233209ff23fSmrg break; 1234209ff23fSmrg case 6: 1235209ff23fSmrg reg = id & 0x1fff; 1236209ff23fSmrg val = RADEON_BIOS8(index); 1237209ff23fSmrg index += 1; 1238209ff23fSmrg ErrorF("i2c write: 0x%x, 0x%x\n", (unsigned)reg, 1239209ff23fSmrg (unsigned)val); 1240209ff23fSmrg RADEONDVOWriteByte(radeon_output->DVOChip, reg, val); 1241209ff23fSmrg break; 1242209ff23fSmrg default: 1243209ff23fSmrg ErrorF("unknown id %d\n", id>>13); 1244209ff23fSmrg return FALSE; 1245209ff23fSmrg }; 1246209ff23fSmrg id = RADEON_BIOS16(index); 1247209ff23fSmrg } 1248209ff23fSmrg return TRUE; 1249209ff23fSmrg } 1250209ff23fSmrg } 1251209ff23fSmrg 1252209ff23fSmrg return FALSE; 1253209ff23fSmrg} 1254209ff23fSmrg 1255209ff23fSmrg/* support for init from bios tables 1256209ff23fSmrg * 1257209ff23fSmrg * Based heavily on the netbsd radeonfb driver 1258209ff23fSmrg * Written by Garrett D'Amore 1259209ff23fSmrg * Copyright (c) 2006 Itronix Inc. 1260209ff23fSmrg * 1261209ff23fSmrg */ 1262209ff23fSmrg 1263209ff23fSmrg/* bios table defines */ 1264209ff23fSmrg 1265209ff23fSmrg#define RADEON_TABLE_ENTRY_FLAG_MASK 0xe000 1266209ff23fSmrg#define RADEON_TABLE_ENTRY_INDEX_MASK 0x1fff 1267209ff23fSmrg#define RADEON_TABLE_ENTRY_COMMAND_MASK 0x00ff 1268209ff23fSmrg 1269209ff23fSmrg#define RADEON_TABLE_FLAG_WRITE_INDEXED 0x0000 1270209ff23fSmrg#define RADEON_TABLE_FLAG_WRITE_DIRECT 0x2000 1271209ff23fSmrg#define RADEON_TABLE_FLAG_MASK_INDEXED 0x4000 1272209ff23fSmrg#define RADEON_TABLE_FLAG_MASK_DIRECT 0x6000 1273209ff23fSmrg#define RADEON_TABLE_FLAG_DELAY 0x8000 1274209ff23fSmrg#define RADEON_TABLE_FLAG_SCOMMAND 0xa000 1275209ff23fSmrg 1276209ff23fSmrg#define RADEON_TABLE_SCOMMAND_WAIT_MC_BUSY_MASK 0x03 1277209ff23fSmrg#define RADEON_TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE 0x08 1278209ff23fSmrg 1279209ff23fSmrg#define RADEON_PLL_FLAG_MASK 0xc0 1280209ff23fSmrg#define RADEON_PLL_INDEX_MASK 0x3f 1281209ff23fSmrg 1282209ff23fSmrg#define RADEON_PLL_FLAG_WRITE 0x00 1283209ff23fSmrg#define RADEON_PLL_FLAG_MASK_BYTE 0x40 1284209ff23fSmrg#define RADEON_PLL_FLAG_WAIT 0x80 1285209ff23fSmrg 1286209ff23fSmrg#define RADEON_PLL_WAIT_150MKS 1 1287209ff23fSmrg#define RADEON_PLL_WAIT_5MS 2 1288209ff23fSmrg#define RADEON_PLL_WAIT_MC_BUSY_MASK 3 1289209ff23fSmrg#define RADEON_PLL_WAIT_DLL_READY_MASK 4 1290209ff23fSmrg#define RADEON_PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24 5 1291209ff23fSmrg 1292209ff23fSmrgstatic uint16_t 1293209ff23fSmrgRADEONValidateBIOSOffset(ScrnInfoPtr pScrn, uint16_t offset) 1294209ff23fSmrg{ 1295209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 1296209ff23fSmrg uint8_t revision = RADEON_BIOS8(offset - 1); 1297209ff23fSmrg 1298209ff23fSmrg if (revision > 0x10) { 1299209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1300209ff23fSmrg "Bad revision %d for BIOS table\n", revision); 1301209ff23fSmrg return 0; 1302209ff23fSmrg } 1303209ff23fSmrg 1304209ff23fSmrg if (offset < 0x60) { 1305209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1306209ff23fSmrg "Bad offset 0x%x for BIOS Table\n", offset); 1307209ff23fSmrg return 0; 1308209ff23fSmrg } 1309209ff23fSmrg 1310209ff23fSmrg return offset; 1311209ff23fSmrg} 1312209ff23fSmrg 1313209ff23fSmrgBool 1314209ff23fSmrgRADEONGetBIOSInitTableOffsets(ScrnInfoPtr pScrn) 1315209ff23fSmrg{ 1316209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 1317209ff23fSmrg uint8_t val; 1318209ff23fSmrg 1319209ff23fSmrg if (!info->VBIOS) { 1320209ff23fSmrg return FALSE; 1321209ff23fSmrg } else { 1322209ff23fSmrg if (info->IsAtomBios) { 1323209ff23fSmrg return FALSE; 1324209ff23fSmrg } else { 1325209ff23fSmrg info->BiosTable.revision = RADEON_BIOS8(info->ROMHeaderStart + 4); 1326209ff23fSmrg info->BiosTable.rr1_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x0c); 1327209ff23fSmrg if (info->BiosTable.rr1_offset) { 1328209ff23fSmrg info->BiosTable.rr1_offset = 1329209ff23fSmrg RADEONValidateBIOSOffset(pScrn, info->BiosTable.rr1_offset); 1330209ff23fSmrg } 1331209ff23fSmrg if (info->BiosTable.revision > 0x09) 1332209ff23fSmrg return TRUE; 1333209ff23fSmrg info->BiosTable.rr2_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x4e); 1334209ff23fSmrg if (info->BiosTable.rr2_offset) { 1335209ff23fSmrg info->BiosTable.rr2_offset = 1336209ff23fSmrg RADEONValidateBIOSOffset(pScrn, info->BiosTable.rr2_offset); 1337209ff23fSmrg } 1338209ff23fSmrg info->BiosTable.dyn_clk_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x52); 1339209ff23fSmrg if (info->BiosTable.dyn_clk_offset) { 1340209ff23fSmrg info->BiosTable.dyn_clk_offset = 1341209ff23fSmrg RADEONValidateBIOSOffset(pScrn, info->BiosTable.dyn_clk_offset); 1342209ff23fSmrg } 1343209ff23fSmrg info->BiosTable.pll_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x46); 1344209ff23fSmrg if (info->BiosTable.pll_offset) { 1345209ff23fSmrg info->BiosTable.pll_offset = 1346209ff23fSmrg RADEONValidateBIOSOffset(pScrn, info->BiosTable.pll_offset); 1347209ff23fSmrg } 1348209ff23fSmrg info->BiosTable.mem_config_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x48); 1349209ff23fSmrg if (info->BiosTable.mem_config_offset) { 1350209ff23fSmrg info->BiosTable.mem_config_offset = 1351209ff23fSmrg RADEONValidateBIOSOffset(pScrn, info->BiosTable.mem_config_offset); 1352209ff23fSmrg } 1353209ff23fSmrg if (info->BiosTable.mem_config_offset) { 1354209ff23fSmrg info->BiosTable.mem_reset_offset = info->BiosTable.mem_config_offset; 1355209ff23fSmrg if (info->BiosTable.mem_reset_offset) { 1356209ff23fSmrg while (RADEON_BIOS8(info->BiosTable.mem_reset_offset)) 1357209ff23fSmrg info->BiosTable.mem_reset_offset++; 1358209ff23fSmrg info->BiosTable.mem_reset_offset++; 1359209ff23fSmrg info->BiosTable.mem_reset_offset += 2; 1360209ff23fSmrg } 1361209ff23fSmrg } 1362209ff23fSmrg if (info->BiosTable.mem_config_offset) { 1363209ff23fSmrg info->BiosTable.short_mem_offset = info->BiosTable.mem_config_offset; 1364209ff23fSmrg if ((info->BiosTable.short_mem_offset != 0) && 1365209ff23fSmrg (RADEON_BIOS8(info->BiosTable.short_mem_offset - 2) <= 64)) 1366209ff23fSmrg info->BiosTable.short_mem_offset += 1367209ff23fSmrg RADEON_BIOS8(info->BiosTable.short_mem_offset - 3); 1368209ff23fSmrg } 1369209ff23fSmrg if (info->BiosTable.rr2_offset) { 1370209ff23fSmrg info->BiosTable.rr3_offset = info->BiosTable.rr2_offset; 1371209ff23fSmrg if (info->BiosTable.rr3_offset) { 1372209ff23fSmrg while ((val = RADEON_BIOS8(info->BiosTable.rr3_offset + 1)) != 0) { 1373209ff23fSmrg if (val & 0x40) 1374209ff23fSmrg info->BiosTable.rr3_offset += 10; 1375209ff23fSmrg else if (val & 0x80) 1376209ff23fSmrg info->BiosTable.rr3_offset += 4; 1377209ff23fSmrg else 1378209ff23fSmrg info->BiosTable.rr3_offset += 6; 1379209ff23fSmrg } 1380209ff23fSmrg info->BiosTable.rr3_offset += 2; 1381209ff23fSmrg } 1382209ff23fSmrg } 1383209ff23fSmrg 1384209ff23fSmrg if (info->BiosTable.rr3_offset) { 1385209ff23fSmrg info->BiosTable.rr4_offset = info->BiosTable.rr3_offset; 1386209ff23fSmrg if (info->BiosTable.rr4_offset) { 1387209ff23fSmrg while ((val = RADEON_BIOS8(info->BiosTable.rr4_offset + 1)) != 0) { 1388209ff23fSmrg if (val & 0x40) 1389209ff23fSmrg info->BiosTable.rr4_offset += 10; 1390209ff23fSmrg else if (val & 0x80) 1391209ff23fSmrg info->BiosTable.rr4_offset += 4; 1392209ff23fSmrg else 1393209ff23fSmrg info->BiosTable.rr4_offset += 6; 1394209ff23fSmrg } 1395209ff23fSmrg info->BiosTable.rr4_offset += 2; 1396209ff23fSmrg } 1397209ff23fSmrg } 1398209ff23fSmrg 1399209ff23fSmrg if (info->BiosTable.rr3_offset + 1 == info->BiosTable.pll_offset) { 1400209ff23fSmrg info->BiosTable.rr3_offset = 0; 1401209ff23fSmrg info->BiosTable.rr4_offset = 0; 1402209ff23fSmrg } 1403209ff23fSmrg 1404209ff23fSmrg return TRUE; 1405209ff23fSmrg 1406209ff23fSmrg } 1407209ff23fSmrg } 1408209ff23fSmrg} 1409209ff23fSmrg 1410209ff23fSmrgstatic void 1411209ff23fSmrgRADEONRestoreBIOSRegBlock(ScrnInfoPtr pScrn, uint16_t table_offset) 1412209ff23fSmrg{ 1413209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 1414209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 1415209ff23fSmrg uint16_t offset = table_offset; 1416209ff23fSmrg uint16_t value, flag, index, count; 1417209ff23fSmrg uint32_t andmask, ormask, val, channel_complete_mask; 1418209ff23fSmrg uint8_t command; 1419209ff23fSmrg 1420209ff23fSmrg if (offset == 0) 1421209ff23fSmrg return; 1422209ff23fSmrg 1423209ff23fSmrg while ((value = RADEON_BIOS16(offset)) != 0) { 1424209ff23fSmrg flag = value & RADEON_TABLE_ENTRY_FLAG_MASK; 1425209ff23fSmrg index = value & RADEON_TABLE_ENTRY_INDEX_MASK; 1426209ff23fSmrg command = value & RADEON_TABLE_ENTRY_COMMAND_MASK; 1427209ff23fSmrg 1428209ff23fSmrg offset += 2; 1429209ff23fSmrg 1430209ff23fSmrg switch (flag) { 1431209ff23fSmrg case RADEON_TABLE_FLAG_WRITE_INDEXED: 1432209ff23fSmrg val = RADEON_BIOS32(offset); 1433209ff23fSmrg ErrorF("WRITE INDEXED: 0x%x 0x%x\n", 1434209ff23fSmrg index, (unsigned)val); 1435209ff23fSmrg OUTREG(RADEON_MM_INDEX, index); 1436209ff23fSmrg OUTREG(RADEON_MM_DATA, val); 1437209ff23fSmrg offset += 4; 1438209ff23fSmrg break; 1439209ff23fSmrg 1440209ff23fSmrg case RADEON_TABLE_FLAG_WRITE_DIRECT: 1441209ff23fSmrg val = RADEON_BIOS32(offset); 1442209ff23fSmrg ErrorF("WRITE DIRECT: 0x%x 0x%x\n", index, (unsigned)val); 1443209ff23fSmrg OUTREG(index, val); 1444209ff23fSmrg offset += 4; 1445209ff23fSmrg break; 1446209ff23fSmrg 1447209ff23fSmrg case RADEON_TABLE_FLAG_MASK_INDEXED: 1448209ff23fSmrg andmask = RADEON_BIOS32(offset); 1449209ff23fSmrg offset += 4; 1450209ff23fSmrg ormask = RADEON_BIOS32(offset); 1451209ff23fSmrg offset += 4; 1452209ff23fSmrg ErrorF("MASK INDEXED: 0x%x 0x%x 0x%x\n", 1453209ff23fSmrg index, (unsigned)andmask, (unsigned)ormask); 1454209ff23fSmrg OUTREG(RADEON_MM_INDEX, index); 1455209ff23fSmrg val = INREG(RADEON_MM_DATA); 1456209ff23fSmrg val = (val & andmask) | ormask; 1457209ff23fSmrg OUTREG(RADEON_MM_DATA, val); 1458209ff23fSmrg break; 1459209ff23fSmrg 1460209ff23fSmrg case RADEON_TABLE_FLAG_MASK_DIRECT: 1461209ff23fSmrg andmask = RADEON_BIOS32(offset); 1462209ff23fSmrg offset += 4; 1463209ff23fSmrg ormask = RADEON_BIOS32(offset); 1464209ff23fSmrg offset += 4; 1465209ff23fSmrg ErrorF("MASK DIRECT: 0x%x 0x%x 0x%x\n", 1466209ff23fSmrg index, (unsigned)andmask, (unsigned)ormask); 1467209ff23fSmrg val = INREG(index); 1468209ff23fSmrg val = (val & andmask) | ormask; 1469209ff23fSmrg OUTREG(index, val); 1470209ff23fSmrg break; 1471209ff23fSmrg 1472209ff23fSmrg case RADEON_TABLE_FLAG_DELAY: 1473209ff23fSmrg count = RADEON_BIOS16(offset); 1474209ff23fSmrg ErrorF("delay: %d\n", count); 1475209ff23fSmrg usleep(count); 1476209ff23fSmrg offset += 2; 1477209ff23fSmrg break; 1478209ff23fSmrg 1479209ff23fSmrg case RADEON_TABLE_FLAG_SCOMMAND: 1480209ff23fSmrg ErrorF("SCOMMAND 0x%x\n", command); 1481209ff23fSmrg switch (command) { 1482209ff23fSmrg case RADEON_TABLE_SCOMMAND_WAIT_MC_BUSY_MASK: 1483209ff23fSmrg count = RADEON_BIOS16(offset); 1484209ff23fSmrg ErrorF("SCOMMAND_WAIT_MC_BUSY_MASK %d\n", count); 1485209ff23fSmrg while (count--) { 1486209ff23fSmrg if (!(INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) & 1487209ff23fSmrg RADEON_MC_BUSY)) 1488209ff23fSmrg break; 1489209ff23fSmrg } 1490209ff23fSmrg break; 1491209ff23fSmrg 1492209ff23fSmrg case RADEON_TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE: 1493209ff23fSmrg count = RADEON_BIOS16(offset); 1494209ff23fSmrg ErrorF("SCOMMAND_WAIT_MEM_PWRUP_COMPLETE %d\n", count); 1495209ff23fSmrg /* may need to take into account how many memory channels 1496209ff23fSmrg * each card has 1497209ff23fSmrg */ 1498209ff23fSmrg if (IS_R300_VARIANT) 1499209ff23fSmrg channel_complete_mask = R300_MEM_PWRUP_COMPLETE; 1500209ff23fSmrg else 1501209ff23fSmrg channel_complete_mask = RADEON_MEM_PWRUP_COMPLETE; 1502209ff23fSmrg while (count--) { 1503209ff23fSmrg /* XXX: may need indexed access */ 1504209ff23fSmrg if ((INREG(RADEON_MEM_STR_CNTL) & 1505209ff23fSmrg channel_complete_mask) == 1506209ff23fSmrg channel_complete_mask) 1507209ff23fSmrg break; 1508209ff23fSmrg } 1509209ff23fSmrg break; 1510209ff23fSmrg 1511209ff23fSmrg } 1512209ff23fSmrg offset += 2; 1513209ff23fSmrg break; 1514209ff23fSmrg } 1515209ff23fSmrg } 1516209ff23fSmrg} 1517209ff23fSmrg 1518209ff23fSmrgstatic void 1519209ff23fSmrgRADEONRestoreBIOSMemBlock(ScrnInfoPtr pScrn, uint16_t table_offset) 1520209ff23fSmrg{ 1521209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 1522209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 1523209ff23fSmrg uint16_t offset = table_offset; 1524209ff23fSmrg uint16_t count; 1525209ff23fSmrg uint32_t ormask, val, channel_complete_mask; 1526209ff23fSmrg uint8_t index; 1527209ff23fSmrg 1528209ff23fSmrg if (offset == 0) 1529209ff23fSmrg return; 1530209ff23fSmrg 1531209ff23fSmrg while ((index = RADEON_BIOS8(offset)) != 0xff) { 1532209ff23fSmrg offset++; 1533209ff23fSmrg if (index == 0x0f) { 1534209ff23fSmrg count = 20000; 1535209ff23fSmrg ErrorF("MEM_WAIT_MEM_PWRUP_COMPLETE %d\n", count); 1536209ff23fSmrg /* may need to take into account how many memory channels 1537209ff23fSmrg * each card has 1538209ff23fSmrg */ 1539209ff23fSmrg if (IS_R300_VARIANT) 1540209ff23fSmrg channel_complete_mask = R300_MEM_PWRUP_COMPLETE; 1541209ff23fSmrg else 1542209ff23fSmrg channel_complete_mask = RADEON_MEM_PWRUP_COMPLETE; 1543209ff23fSmrg while (count--) { 1544209ff23fSmrg /* XXX: may need indexed access */ 1545209ff23fSmrg if ((INREG(RADEON_MEM_STR_CNTL) & 1546209ff23fSmrg channel_complete_mask) == 1547209ff23fSmrg channel_complete_mask) 1548209ff23fSmrg break; 1549209ff23fSmrg } 1550209ff23fSmrg } else { 1551209ff23fSmrg ormask = RADEON_BIOS16(offset); 1552209ff23fSmrg offset += 2; 1553209ff23fSmrg 1554209ff23fSmrg ErrorF("INDEX RADEON_MEM_SDRAM_MODE_REG %x %x\n", 1555209ff23fSmrg RADEON_SDRAM_MODE_MASK, (unsigned)ormask); 1556209ff23fSmrg 1557209ff23fSmrg /* can this use direct access? */ 1558209ff23fSmrg OUTREG(RADEON_MM_INDEX, RADEON_MEM_SDRAM_MODE_REG); 1559209ff23fSmrg val = INREG(RADEON_MM_DATA); 1560209ff23fSmrg val = (val & RADEON_SDRAM_MODE_MASK) | ormask; 1561209ff23fSmrg OUTREG(RADEON_MM_DATA, val); 1562209ff23fSmrg 1563209ff23fSmrg ormask = (uint32_t)index << 24; 1564209ff23fSmrg 1565209ff23fSmrg ErrorF("INDEX RADEON_MEM_SDRAM_MODE_REG %x %x\n", 1566209ff23fSmrg RADEON_B3MEM_RESET_MASK, (unsigned)ormask); 1567209ff23fSmrg 1568209ff23fSmrg /* can this use direct access? */ 1569209ff23fSmrg OUTREG(RADEON_MM_INDEX, RADEON_MEM_SDRAM_MODE_REG); 1570209ff23fSmrg val = INREG(RADEON_MM_DATA); 1571209ff23fSmrg val = (val & RADEON_B3MEM_RESET_MASK) | ormask; 1572209ff23fSmrg OUTREG(RADEON_MM_DATA, val); 1573209ff23fSmrg } 1574209ff23fSmrg } 1575209ff23fSmrg} 1576209ff23fSmrg 1577209ff23fSmrgstatic void 1578209ff23fSmrgRADEONRestoreBIOSPllBlock(ScrnInfoPtr pScrn, uint16_t table_offset) 1579209ff23fSmrg{ 1580209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 1581209ff23fSmrg uint16_t offset = table_offset; 1582209ff23fSmrg uint8_t index, shift; 1583209ff23fSmrg uint32_t andmask, ormask, val, clk_pwrmgt_cntl; 1584209ff23fSmrg uint16_t count; 1585209ff23fSmrg 1586209ff23fSmrg if (offset == 0) 1587209ff23fSmrg return; 1588209ff23fSmrg 1589209ff23fSmrg while ((index = RADEON_BIOS8(offset)) != 0) { 1590209ff23fSmrg offset++; 1591209ff23fSmrg 1592209ff23fSmrg switch (index & RADEON_PLL_FLAG_MASK) { 1593209ff23fSmrg case RADEON_PLL_FLAG_WAIT: 1594209ff23fSmrg switch (index & RADEON_PLL_INDEX_MASK) { 1595209ff23fSmrg case RADEON_PLL_WAIT_150MKS: 1596209ff23fSmrg ErrorF("delay: 150 us\n"); 1597209ff23fSmrg usleep(150); 1598209ff23fSmrg break; 1599209ff23fSmrg case RADEON_PLL_WAIT_5MS: 1600209ff23fSmrg ErrorF("delay: 5 ms\n"); 1601209ff23fSmrg usleep(5000); 1602209ff23fSmrg break; 1603209ff23fSmrg 1604209ff23fSmrg case RADEON_PLL_WAIT_MC_BUSY_MASK: 1605209ff23fSmrg count = 1000; 1606209ff23fSmrg ErrorF("PLL_WAIT_MC_BUSY_MASK %d\n", count); 1607209ff23fSmrg while (count--) { 1608209ff23fSmrg if (!(INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) & 1609209ff23fSmrg RADEON_MC_BUSY)) 1610209ff23fSmrg break; 1611209ff23fSmrg } 1612209ff23fSmrg break; 1613209ff23fSmrg 1614209ff23fSmrg case RADEON_PLL_WAIT_DLL_READY_MASK: 1615209ff23fSmrg count = 1000; 1616209ff23fSmrg ErrorF("PLL_WAIT_DLL_READY_MASK %d\n", count); 1617209ff23fSmrg while (count--) { 1618209ff23fSmrg if (INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) & 1619209ff23fSmrg RADEON_DLL_READY) 1620209ff23fSmrg break; 1621209ff23fSmrg } 1622209ff23fSmrg break; 1623209ff23fSmrg 1624209ff23fSmrg case RADEON_PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24: 1625209ff23fSmrg ErrorF("PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24\n"); 1626209ff23fSmrg clk_pwrmgt_cntl = INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL); 1627209ff23fSmrg if (clk_pwrmgt_cntl & RADEON_CG_NO1_DEBUG_0) { 1628209ff23fSmrg val = INPLL(pScrn, RADEON_MCLK_CNTL); 1629209ff23fSmrg /* is this right? */ 1630209ff23fSmrg val = (val & 0xFFFF0000) | 0x1111; /* seems like we should clear these... */ 1631209ff23fSmrg OUTPLL(pScrn, RADEON_MCLK_CNTL, val); 1632209ff23fSmrg usleep(10000); 1633209ff23fSmrg OUTPLL(pScrn, RADEON_CLK_PWRMGT_CNTL, 1634209ff23fSmrg clk_pwrmgt_cntl & ~RADEON_CG_NO1_DEBUG_0); 1635209ff23fSmrg usleep(10000); 1636209ff23fSmrg } 1637209ff23fSmrg break; 1638209ff23fSmrg } 1639209ff23fSmrg break; 1640209ff23fSmrg 1641209ff23fSmrg case RADEON_PLL_FLAG_MASK_BYTE: 1642209ff23fSmrg shift = RADEON_BIOS8(offset) * 8; 1643209ff23fSmrg offset++; 1644209ff23fSmrg 1645209ff23fSmrg andmask = 1646209ff23fSmrg (((uint32_t)RADEON_BIOS8(offset)) << shift) | 1647209ff23fSmrg ~((uint32_t)0xff << shift); 1648209ff23fSmrg offset++; 1649209ff23fSmrg 1650209ff23fSmrg ormask = ((uint32_t)RADEON_BIOS8(offset)) << shift; 1651209ff23fSmrg offset++; 1652209ff23fSmrg 1653209ff23fSmrg ErrorF("PLL_MASK_BYTE 0x%x 0x%x 0x%x 0x%x\n", 1654209ff23fSmrg index, shift, (unsigned)andmask, (unsigned)ormask); 1655209ff23fSmrg val = INPLL(pScrn, index); 1656209ff23fSmrg val = (val & andmask) | ormask; 1657209ff23fSmrg OUTPLL(pScrn, index, val); 1658209ff23fSmrg break; 1659209ff23fSmrg 1660209ff23fSmrg case RADEON_PLL_FLAG_WRITE: 1661209ff23fSmrg val = RADEON_BIOS32(offset); 1662209ff23fSmrg ErrorF("PLL_WRITE 0x%x 0x%x\n", index, (unsigned)val); 1663209ff23fSmrg OUTPLL(pScrn, index, val); 1664209ff23fSmrg offset += 4; 1665209ff23fSmrg break; 1666209ff23fSmrg } 1667209ff23fSmrg } 1668209ff23fSmrg} 1669209ff23fSmrg 1670209ff23fSmrgBool 1671209ff23fSmrgRADEONPostCardFromBIOSTables(ScrnInfoPtr pScrn) 1672209ff23fSmrg{ 1673209ff23fSmrg RADEONInfoPtr info = RADEONPTR (pScrn); 1674209ff23fSmrg 1675209ff23fSmrg if (!info->VBIOS) { 1676209ff23fSmrg return FALSE; 1677209ff23fSmrg } else { 1678209ff23fSmrg if (info->IsAtomBios) { 1679209ff23fSmrg return FALSE; 1680209ff23fSmrg } else { 1681209ff23fSmrg if (info->BiosTable.rr1_offset) { 1682209ff23fSmrg ErrorF("rr1 restore, 0x%x\n", info->BiosTable.rr1_offset); 1683209ff23fSmrg RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr1_offset); 1684209ff23fSmrg } 1685209ff23fSmrg if (info->BiosTable.revision < 0x09) { 1686209ff23fSmrg if (info->BiosTable.pll_offset) { 1687209ff23fSmrg ErrorF("pll restore, 0x%x\n", info->BiosTable.pll_offset); 1688209ff23fSmrg RADEONRestoreBIOSPllBlock(pScrn, info->BiosTable.pll_offset); 1689209ff23fSmrg } 1690209ff23fSmrg if (info->BiosTable.rr2_offset) { 1691209ff23fSmrg ErrorF("rr2 restore, 0x%x\n", info->BiosTable.rr2_offset); 1692209ff23fSmrg RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr2_offset); 1693209ff23fSmrg } 1694209ff23fSmrg if (info->BiosTable.rr4_offset) { 1695209ff23fSmrg ErrorF("rr4 restore, 0x%x\n", info->BiosTable.rr4_offset); 1696209ff23fSmrg RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr4_offset); 1697209ff23fSmrg } 1698209ff23fSmrg if (info->BiosTable.mem_reset_offset) { 1699209ff23fSmrg ErrorF("mem reset restore, 0x%x\n", info->BiosTable.mem_reset_offset); 1700209ff23fSmrg RADEONRestoreBIOSMemBlock(pScrn, info->BiosTable.mem_reset_offset); 1701209ff23fSmrg } 1702209ff23fSmrg if (info->BiosTable.rr3_offset) { 1703209ff23fSmrg ErrorF("rr3 restore, 0x%x\n", info->BiosTable.rr3_offset); 1704209ff23fSmrg RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr3_offset); 1705209ff23fSmrg } 1706209ff23fSmrg if (info->BiosTable.dyn_clk_offset) { 1707209ff23fSmrg ErrorF("dyn_clk restore, 0x%x\n", info->BiosTable.dyn_clk_offset); 1708209ff23fSmrg RADEONRestoreBIOSPllBlock(pScrn, info->BiosTable.dyn_clk_offset); 1709209ff23fSmrg } 1710209ff23fSmrg } 1711209ff23fSmrg } 1712209ff23fSmrg } 1713209ff23fSmrg return TRUE; 1714209ff23fSmrg} 1715