radeon_bios.c revision c503f109
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
101b7e1c893Smrgradeon_read_disabled_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
269b7e1c893SmrgBool
270b7e1c893Smrgradeon_card_posted(ScrnInfoPtr pScrn)
271b7e1c893Smrg{
272b7e1c893Smrg    RADEONInfoPtr info     = RADEONPTR(pScrn);
273b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
274b7e1c893Smrg    uint32_t reg;
275b7e1c893Smrg
276c503f109Smrg    /* first check CRTCs */
277b7e1c893Smrg    if (IS_AVIVO_VARIANT) {
278b7e1c893Smrg	reg = INREG(AVIVO_D1CRTC_CONTROL) | INREG(AVIVO_D2CRTC_CONTROL);
279b7e1c893Smrg	if (reg & AVIVO_CRTC_EN)
280b7e1c893Smrg	    return TRUE;
281b7e1c893Smrg    } else {
282b7e1c893Smrg	reg = INREG(RADEON_CRTC_GEN_CNTL) | INREG(RADEON_CRTC2_GEN_CNTL);
283b7e1c893Smrg	if (reg & RADEON_CRTC_EN)
284b7e1c893Smrg	    return TRUE;
285b7e1c893Smrg    }
286b7e1c893Smrg
287c503f109Smrg    /* then check MEM_SIZE, in case something turned the crtcs off */
288c503f109Smrg    if (info->ChipFamily >= CHIP_FAMILY_R600)
289c503f109Smrg	reg = INREG(R600_CONFIG_MEMSIZE);
290c503f109Smrg    else
291c503f109Smrg	reg = INREG(RADEON_CONFIG_MEMSIZE);
292c503f109Smrg
293c503f109Smrg    if (reg)
294c503f109Smrg	return TRUE;
295c503f109Smrg
296b7e1c893Smrg    return FALSE;
297b7e1c893Smrg}
298b7e1c893Smrg
299209ff23fSmrg/* Read the Video BIOS block and the FP registers (if applicable). */
300209ff23fSmrgBool
301209ff23fSmrgRADEONGetBIOSInfo(ScrnInfoPtr pScrn, xf86Int10InfoPtr  pInt10)
302209ff23fSmrg{
303209ff23fSmrg    RADEONInfoPtr info     = RADEONPTR(pScrn);
304209ff23fSmrg    int tmp;
305209ff23fSmrg    unsigned short dptr;
306209ff23fSmrg
307209ff23fSmrg#ifdef XSERVER_LIBPCIACCESS
308209ff23fSmrg    int size = info->PciInfo->rom_size > RADEON_VBIOS_SIZE ? info->PciInfo->rom_size : RADEON_VBIOS_SIZE;
309209ff23fSmrg    info->VBIOS = xalloc(size);
310209ff23fSmrg#else
311209ff23fSmrg    info->VBIOS = xalloc(RADEON_VBIOS_SIZE);
312209ff23fSmrg#endif
313209ff23fSmrg    if (!info->VBIOS) {
314209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
315209ff23fSmrg		   "Cannot allocate space for hold Video BIOS!\n");
316209ff23fSmrg	return FALSE;
317209ff23fSmrg    } else {
318209ff23fSmrg	if (pInt10) {
319209ff23fSmrg	    info->BIOSAddr = pInt10->BIOSseg << 4;
320209ff23fSmrg	    (void)memcpy(info->VBIOS, xf86int10Addr(pInt10, info->BIOSAddr),
321209ff23fSmrg			 RADEON_VBIOS_SIZE);
322b7e1c893Smrg	} else if (!radeon_read_bios(pScrn))
323b7e1c893Smrg	    (void)radeon_read_disabled_bios(pScrn);
324209ff23fSmrg    }
325209ff23fSmrg
326209ff23fSmrg    if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) {
327209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
328209ff23fSmrg		   "Unrecognized BIOS signature, BIOS data will not be used\n");
329209ff23fSmrg	xfree (info->VBIOS);
330209ff23fSmrg	info->VBIOS = NULL;
331209ff23fSmrg	return FALSE;
332209ff23fSmrg    }
333209ff23fSmrg
334209ff23fSmrg    /* Verify it's an x86 BIOS not OF firmware, copied from radeonfb */
335209ff23fSmrg    dptr = RADEON_BIOS16(0x18);
336209ff23fSmrg    /* If PCI data signature is wrong assume x86 video BIOS anyway */
337209ff23fSmrg    if (RADEON_BIOS32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
338209ff23fSmrg       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
339209ff23fSmrg		   "ROM PCI data signature incorrect, ignoring\n");
340209ff23fSmrg    }
341209ff23fSmrg    else if (info->VBIOS[dptr + 0x14] != 0x0) {
342209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
343209ff23fSmrg		   "Not an x86 BIOS ROM image, BIOS data will not be used\n");
344209ff23fSmrg	xfree (info->VBIOS);
345209ff23fSmrg	info->VBIOS = NULL;
346209ff23fSmrg	return FALSE;
347209ff23fSmrg    }
348209ff23fSmrg
349209ff23fSmrg    if (info->VBIOS) info->ROMHeaderStart = RADEON_BIOS16(0x48);
350209ff23fSmrg
351209ff23fSmrg    if(!info->ROMHeaderStart) {
352209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
353209ff23fSmrg		   "Invalid ROM pointer, BIOS data will not be used\n");
354209ff23fSmrg	xfree (info->VBIOS);
355209ff23fSmrg	info->VBIOS = NULL;
356209ff23fSmrg	return FALSE;
357209ff23fSmrg    }
358b7e1c893Smrg
359209ff23fSmrg    tmp = info->ROMHeaderStart + 4;
360209ff23fSmrg    if ((RADEON_BIOS8(tmp)   == 'A' &&
361209ff23fSmrg	 RADEON_BIOS8(tmp+1) == 'T' &&
362209ff23fSmrg	 RADEON_BIOS8(tmp+2) == 'O' &&
363209ff23fSmrg	 RADEON_BIOS8(tmp+3) == 'M') ||
364209ff23fSmrg	(RADEON_BIOS8(tmp)   == 'M' &&
365209ff23fSmrg	 RADEON_BIOS8(tmp+1) == 'O' &&
366209ff23fSmrg	 RADEON_BIOS8(tmp+2) == 'T' &&
367209ff23fSmrg	 RADEON_BIOS8(tmp+3) == 'A'))
368209ff23fSmrg	info->IsAtomBios = TRUE;
369209ff23fSmrg    else
370209ff23fSmrg	info->IsAtomBios = FALSE;
371209ff23fSmrg
372209ff23fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s BIOS detected\n",
373209ff23fSmrg	       info->IsAtomBios ? "ATOM":"Legacy");
374209ff23fSmrg
375209ff23fSmrg    if (info->IsAtomBios) {
376b7e1c893Smrg	AtomBiosArgRec atomBiosArg;
377209ff23fSmrg
378b7e1c893Smrg	if (RHDAtomBiosFunc(pScrn->scrnIndex, NULL, ATOMBIOS_INIT, &atomBiosArg)
379b7e1c893Smrg	    == ATOM_SUCCESS) {
380b7e1c893Smrg	    info->atomBIOS = atomBiosArg.atomhandle;
381b7e1c893Smrg	}
382209ff23fSmrg
383b7e1c893Smrg	atomBiosArg.fb.start = info->FbFreeStart;
384b7e1c893Smrg	atomBiosArg.fb.size = info->FbFreeSize;
385b7e1c893Smrg	if (RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, ATOMBIOS_ALLOCATE_FB_SCRATCH,
386209ff23fSmrg			    &atomBiosArg) == ATOM_SUCCESS) {
387209ff23fSmrg
388209ff23fSmrg	    info->FbFreeStart = atomBiosArg.fb.start;
389209ff23fSmrg	    info->FbFreeSize = atomBiosArg.fb.size;
390b7e1c893Smrg	}
391b7e1c893Smrg
392b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, GET_DEFAULT_ENGINE_CLOCK,
393b7e1c893Smrg			&atomBiosArg);
394b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, GET_DEFAULT_MEMORY_CLOCK,
395b7e1c893Smrg			&atomBiosArg);
396b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
397b7e1c893Smrg			GET_MAX_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg);
398b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
399b7e1c893Smrg			GET_MIN_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg);
400b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
401b7e1c893Smrg			GET_MAX_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg);
402b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
403209ff23fSmrg			GET_MIN_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg);
404b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
405209ff23fSmrg			GET_MAX_PIXEL_CLK, &atomBiosArg);
406b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
407b7e1c893Smrg			GET_REF_CLOCK, &atomBiosArg);
408209ff23fSmrg
409209ff23fSmrg	info->MasterDataStart = RADEON_BIOS16 (info->ROMHeaderStart + 32);
410209ff23fSmrg    }
411b7e1c893Smrg
412b7e1c893Smrg    /* We are a bit too quick at using this "unposted" to re-post the
413b7e1c893Smrg     * card. This causes some problems with VT switch on some machines,
414b7e1c893Smrg     * so let's work around this for now by only POSTing if none of the
415b7e1c893Smrg     * CRTCs are enabled
416b7e1c893Smrg     */
417b7e1c893Smrg    if ((!radeon_card_posted(pScrn)) && info->VBIOS) {
418b7e1c893Smrg	if (info->IsAtomBios) {
419b7e1c893Smrg	    if (!rhdAtomASICInit(info->atomBIOS))
420b7e1c893Smrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
421b7e1c893Smrg			   "%s: AsicInit failed.\n",__func__);
422b7e1c893Smrg	} else {
423209ff23fSmrg#if 0
424b7e1c893Smrg	    /* FIX ME */
425b7e1c893Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Attempting to POST via legacy BIOS tables\n");
426209ff23fSmrg	    RADEONGetBIOSInitTableOffsets(pScrn);
427209ff23fSmrg	    RADEONPostCardFromBIOSTables(pScrn);
428b7e1c893Smrg#endif
429209ff23fSmrg	}
430209ff23fSmrg    }
431b7e1c893Smrg
432209ff23fSmrg    return TRUE;
433209ff23fSmrg}
434209ff23fSmrg
435209ff23fSmrgstatic Bool RADEONGetATOMConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
436209ff23fSmrg{
437209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
438209ff23fSmrg
439209ff23fSmrg    if (!info->VBIOS) return FALSE;
440b7e1c893Smrg
441209ff23fSmrg    if (RADEONGetATOMConnectorInfoFromBIOSObject(pScrn))
442209ff23fSmrg	return TRUE;
443209ff23fSmrg
444209ff23fSmrg    if (RADEONGetATOMConnectorInfoFromBIOSConnectorTable(pScrn))
445209ff23fSmrg	return TRUE;
446209ff23fSmrg
447209ff23fSmrg    return FALSE;
448209ff23fSmrg}
449209ff23fSmrg
450209ff23fSmrgstatic void RADEONApplyLegacyQuirks(ScrnInfoPtr pScrn, int index)
451209ff23fSmrg{
452209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
453209ff23fSmrg
454b7e1c893Smrg    /* XPRESS DDC quirks */
455209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400 ||
456209ff23fSmrg	 info->ChipFamily == CHIP_FAMILY_RS480) &&
457209ff23fSmrg	info->BiosConnector[index].ddc_i2c.mask_clk_reg == RADEON_GPIO_CRT2_DDC) {
458209ff23fSmrg	info->BiosConnector[index].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID);
459b7e1c893Smrg    } else if ((info->ChipFamily == CHIP_FAMILY_RS400 ||
460b7e1c893Smrg		info->ChipFamily == CHIP_FAMILY_RS480) &&
461b7e1c893Smrg	       info->BiosConnector[index].ddc_i2c.mask_clk_reg == RADEON_GPIO_MONID) {
462b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.valid = TRUE;
463b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.mask_clk_mask = (0x20 << 8);
464b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.mask_data_mask = 0x80;
465b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.a_clk_mask = (0x20 << 8);
466b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.a_data_mask = 0x80;
467b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.put_clk_mask = (0x20 << 8);
468b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.put_data_mask = 0x80;
469b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.get_clk_mask = (0x20 << 8);
470b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.get_data_mask = 0x80;
471b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.mask_clk_reg = RADEON_GPIOPAD_MASK;
472b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.mask_data_reg = RADEON_GPIOPAD_MASK;
473b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.a_clk_reg = RADEON_GPIOPAD_A;
474b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.a_data_reg = RADEON_GPIOPAD_A;
475b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.put_clk_reg = RADEON_GPIOPAD_EN;
476b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.put_data_reg = RADEON_GPIOPAD_EN;
477b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.get_clk_reg = RADEON_LCD_GPIO_Y_REG;
478b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.get_data_reg = RADEON_LCD_GPIO_Y_REG;
479209ff23fSmrg    }
480209ff23fSmrg
481209ff23fSmrg    /* Certain IBM chipset RN50s have a BIOS reporting two VGAs,
482209ff23fSmrg       one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */
483209ff23fSmrg    if (info->Chipset == PCI_CHIP_RN50_515E &&
484209ff23fSmrg	PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1014) {
485209ff23fSmrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_VGA &&
486209ff23fSmrg	    info->BiosConnector[index].ddc_i2c.mask_clk_reg == RADEON_GPIO_CRT2_DDC) {
487209ff23fSmrg	    info->BiosConnector[index].valid = FALSE;
488209ff23fSmrg	}
489209ff23fSmrg    }
490209ff23fSmrg
491209ff23fSmrg    /* Some RV100 cards with 2 VGA ports show up with DVI+VGA */
492209ff23fSmrg    if (info->Chipset == PCI_CHIP_RV100_QY &&
493209ff23fSmrg	PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1002 &&
494209ff23fSmrg	PCI_SUB_DEVICE_ID(info->PciInfo) == 0x013a) {
495209ff23fSmrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_DVI_I) {
496209ff23fSmrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_VGA;
497209ff23fSmrg	}
498209ff23fSmrg    }
499209ff23fSmrg
500b7e1c893Smrg    /* X300 card with extra non-existent DVI port */
501b7e1c893Smrg    if (info->Chipset == PCI_CHIP_RV370_5B60 &&
502b7e1c893Smrg	PCI_SUB_VENDOR_ID(info->PciInfo) == 0x17af &&
503b7e1c893Smrg	PCI_SUB_DEVICE_ID(info->PciInfo) == 0x201e &&
504b7e1c893Smrg	index == 2) {
505b7e1c893Smrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_DVI_I) {
506b7e1c893Smrg	    info->BiosConnector[index].valid = FALSE;
507b7e1c893Smrg	}
508b7e1c893Smrg    }
509b7e1c893Smrg
510b7e1c893Smrg    /* r200 card with primary dac routed to both VGA and DVI - disable load detection
511b7e1c893Smrg     * otherwise you end up detecing load if either port is attached
512b7e1c893Smrg     */
513b7e1c893Smrg    if (info->Chipset == PCI_CHIP_R200_QL &&
514b7e1c893Smrg	PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1569 &&
515b7e1c893Smrg	PCI_SUB_DEVICE_ID(info->PciInfo) == 0x514c &&
516b7e1c893Smrg	(info->BiosConnector[index].devices & ATOM_DEVICE_CRT1_SUPPORT)) {
517b7e1c893Smrg	info->BiosConnector[index].load_detection = FALSE;
518b7e1c893Smrg    }
519b7e1c893Smrg
520209ff23fSmrg}
521209ff23fSmrg
522209ff23fSmrgstatic Bool RADEONGetLegacyConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
523209ff23fSmrg{
524209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
525209ff23fSmrg    int offset, i, entry, tmp, tmp0, tmp1;
526209ff23fSmrg    RADEONLegacyDDCType DDCType;
527209ff23fSmrg    RADEONLegacyConnectorType ConnectorType;
528209ff23fSmrg
529209ff23fSmrg    if (!info->VBIOS) return FALSE;
530209ff23fSmrg
531209ff23fSmrg    offset = RADEON_BIOS16(info->ROMHeaderStart + 0x50);
532209ff23fSmrg    if (offset) {
533209ff23fSmrg	for (i = 0; i < 4; i++) {
534209ff23fSmrg	    entry = offset + 2 + i*2;
535209ff23fSmrg
536209ff23fSmrg	    if (!RADEON_BIOS16(entry)) {
537209ff23fSmrg		break;
538209ff23fSmrg	    }
539209ff23fSmrg	    info->BiosConnector[i].valid = TRUE;
540209ff23fSmrg	    tmp = RADEON_BIOS16(entry);
541209ff23fSmrg	    info->BiosConnector[i].ConnectorType = (tmp >> 12) & 0xf;
542209ff23fSmrg	    ConnectorType = (tmp >> 12) & 0xf;
543209ff23fSmrg	    switch (ConnectorType) {
544209ff23fSmrg	    case CONNECTOR_PROPRIETARY_LEGACY:
545b7e1c893Smrg		info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_D;
546b7e1c893Smrg		if ((tmp >> 4) & 0x1) {
547b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP2_SUPPORT;
548b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
549b7e1c893Smrg				       radeon_get_encoder_id_from_supported_device(pScrn,
550b7e1c893Smrg										   ATOM_DEVICE_DFP2_SUPPORT,
551b7e1c893Smrg										   0),
552b7e1c893Smrg					    ATOM_DEVICE_DFP2_SUPPORT))
553b7e1c893Smrg			return FALSE;
554b7e1c893Smrg		} else {
555b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP1_SUPPORT;
556b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
557b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
558b7e1c893Smrg											ATOM_DEVICE_DFP1_SUPPORT,
559b7e1c893Smrg											0),
560b7e1c893Smrg					    ATOM_DEVICE_DFP1_SUPPORT))
561b7e1c893Smrg			return FALSE;
562b7e1c893Smrg		}
563209ff23fSmrg		break;
564209ff23fSmrg	    case CONNECTOR_CRT_LEGACY:
565209ff23fSmrg		info->BiosConnector[i].ConnectorType = CONNECTOR_VGA;
566b7e1c893Smrg		if (tmp & 0x1) {
567b7e1c893Smrg		    info->BiosConnector[i].load_detection = FALSE;
568b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_CRT2_SUPPORT;
569b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
570b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
571b7e1c893Smrg											ATOM_DEVICE_CRT2_SUPPORT,
572b7e1c893Smrg											2),
573b7e1c893Smrg					    ATOM_DEVICE_CRT2_SUPPORT))
574b7e1c893Smrg			return FALSE;
575b7e1c893Smrg		} else {
576b7e1c893Smrg		    info->BiosConnector[i].load_detection = TRUE;
577b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_CRT1_SUPPORT;
578b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
579b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
580b7e1c893Smrg											ATOM_DEVICE_CRT1_SUPPORT,
581b7e1c893Smrg											1),
582b7e1c893Smrg					    ATOM_DEVICE_CRT1_SUPPORT))
583b7e1c893Smrg			return FALSE;
584b7e1c893Smrg		}
585209ff23fSmrg		break;
586209ff23fSmrg	    case CONNECTOR_DVI_I_LEGACY:
587209ff23fSmrg		info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_I;
588b7e1c893Smrg		if (tmp & 0x1) {
589b7e1c893Smrg		    info->BiosConnector[i].load_detection = FALSE;
590b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_CRT2_SUPPORT;
591b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
592b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
593b7e1c893Smrg											ATOM_DEVICE_CRT2_SUPPORT,
594b7e1c893Smrg											2),
595b7e1c893Smrg					    ATOM_DEVICE_CRT2_SUPPORT))
596b7e1c893Smrg			return FALSE;
597b7e1c893Smrg		} else {
598b7e1c893Smrg		    info->BiosConnector[i].load_detection = TRUE;
599b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_CRT1_SUPPORT;
600b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
601b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
602b7e1c893Smrg											ATOM_DEVICE_CRT1_SUPPORT,
603b7e1c893Smrg											1),
604b7e1c893Smrg					    ATOM_DEVICE_CRT1_SUPPORT))
605b7e1c893Smrg			return FALSE;
606b7e1c893Smrg		}
607b7e1c893Smrg		if ((tmp >> 4) & 0x1) {
608b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP2_SUPPORT;
609b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
610b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
611b7e1c893Smrg											ATOM_DEVICE_DFP2_SUPPORT,
612b7e1c893Smrg											0),
613b7e1c893Smrg					    ATOM_DEVICE_DFP2_SUPPORT))
614b7e1c893Smrg			return FALSE;
615b7e1c893Smrg		} else {
616b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP1_SUPPORT;
617b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
618b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
619b7e1c893Smrg											ATOM_DEVICE_DFP1_SUPPORT,
620b7e1c893Smrg											0),
621b7e1c893Smrg					    ATOM_DEVICE_DFP1_SUPPORT))
622b7e1c893Smrg			return FALSE;
623b7e1c893Smrg		}
624209ff23fSmrg		break;
625209ff23fSmrg	    case CONNECTOR_DVI_D_LEGACY:
626209ff23fSmrg		info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_D;
627b7e1c893Smrg		if ((tmp >> 4) & 0x1) {
628b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP2_SUPPORT;
629b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
630b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
631b7e1c893Smrg											ATOM_DEVICE_DFP2_SUPPORT,
632b7e1c893Smrg											0),
633b7e1c893Smrg					    ATOM_DEVICE_DFP2_SUPPORT))
634b7e1c893Smrg			return FALSE;
635b7e1c893Smrg		} else {
636b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP1_SUPPORT;
637b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
638b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
639b7e1c893Smrg											ATOM_DEVICE_DFP1_SUPPORT,
640b7e1c893Smrg											0),
641b7e1c893Smrg					    ATOM_DEVICE_DFP1_SUPPORT))
642b7e1c893Smrg			return FALSE;
643b7e1c893Smrg		}
644209ff23fSmrg		break;
645209ff23fSmrg	    case CONNECTOR_CTV_LEGACY:
646209ff23fSmrg		info->BiosConnector[i].ConnectorType = CONNECTOR_CTV;
647b7e1c893Smrg		info->BiosConnector[i].load_detection = FALSE;
648b7e1c893Smrg		info->BiosConnector[i].devices = ATOM_DEVICE_TV1_SUPPORT;
649b7e1c893Smrg		if (!radeon_add_encoder(pScrn,
650b7e1c893Smrg					radeon_get_encoder_id_from_supported_device(pScrn,
651b7e1c893Smrg										    ATOM_DEVICE_TV1_SUPPORT,
652b7e1c893Smrg										    2),
653b7e1c893Smrg					ATOM_DEVICE_TV1_SUPPORT))
654b7e1c893Smrg		    return FALSE;
655209ff23fSmrg		break;
656209ff23fSmrg	    case CONNECTOR_STV_LEGACY:
657209ff23fSmrg		info->BiosConnector[i].ConnectorType = CONNECTOR_STV;
658b7e1c893Smrg		info->BiosConnector[i].load_detection = FALSE;
659b7e1c893Smrg		info->BiosConnector[i].devices = ATOM_DEVICE_TV1_SUPPORT;
660b7e1c893Smrg		if (!radeon_add_encoder(pScrn,
661b7e1c893Smrg					radeon_get_encoder_id_from_supported_device(pScrn,
662b7e1c893Smrg										    ATOM_DEVICE_TV1_SUPPORT,
663b7e1c893Smrg										    2),
664b7e1c893Smrg					ATOM_DEVICE_TV1_SUPPORT))
665b7e1c893Smrg		    return FALSE;
666209ff23fSmrg		break;
667209ff23fSmrg	    default:
668209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown Connector Type: %d\n", ConnectorType);
669209ff23fSmrg		info->BiosConnector[i].valid = FALSE;
670209ff23fSmrg		break;
671209ff23fSmrg	    }
672209ff23fSmrg
673209ff23fSmrg	    info->BiosConnector[i].ddc_i2c.valid = FALSE;
674209ff23fSmrg
675209ff23fSmrg	    DDCType = (tmp >> 8) & 0xf;
676209ff23fSmrg	    switch (DDCType) {
677209ff23fSmrg	    case DDC_MONID:
678209ff23fSmrg		info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID);
679209ff23fSmrg		break;
680209ff23fSmrg	    case DDC_DVI:
681209ff23fSmrg		info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
682209ff23fSmrg		break;
683209ff23fSmrg	    case DDC_VGA:
684209ff23fSmrg		info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
685209ff23fSmrg		break;
686209ff23fSmrg	    case DDC_CRT2:
687209ff23fSmrg		info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
688209ff23fSmrg		break;
689209ff23fSmrg	    default:
690209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown DDC Type: %d\n", DDCType);
691209ff23fSmrg		break;
692209ff23fSmrg	    }
693209ff23fSmrg
694209ff23fSmrg	    RADEONApplyLegacyQuirks(pScrn, i);
695209ff23fSmrg
696209ff23fSmrg	}
697209ff23fSmrg    } else {
698209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Connector Info Table found!\n");
699209ff23fSmrg
700209ff23fSmrg	/* old radeons and r128 didn't use connector tables you just check
701209ff23fSmrg	 * for LVDS, DVI, TV, etc. tables
702209ff23fSmrg	 */
703209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x34);
704209ff23fSmrg	if (offset) {
705209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
706209ff23fSmrg		       "Found DFP table, assuming DVI connector\n");
707209ff23fSmrg	    info->BiosConnector[0].valid = TRUE;
708209ff23fSmrg	    info->BiosConnector[0].ConnectorType = CONNECTOR_DVI_I;
709b7e1c893Smrg	    info->BiosConnector[0].load_detection = TRUE;
710209ff23fSmrg	    info->BiosConnector[0].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
711b7e1c893Smrg	    info->BiosConnector[0].devices = ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_DFP1_SUPPORT;
712b7e1c893Smrg	    if (!radeon_add_encoder(pScrn,
713b7e1c893Smrg				    radeon_get_encoder_id_from_supported_device(pScrn,
714b7e1c893Smrg										ATOM_DEVICE_DFP1_SUPPORT,
715b7e1c893Smrg										0),
716b7e1c893Smrg				    ATOM_DEVICE_DFP1_SUPPORT))
717b7e1c893Smrg		return FALSE;
718b7e1c893Smrg	    if (!radeon_add_encoder(pScrn,
719b7e1c893Smrg				    radeon_get_encoder_id_from_supported_device(pScrn,
720b7e1c893Smrg										ATOM_DEVICE_CRT1_SUPPORT,
721b7e1c893Smrg										1),
722b7e1c893Smrg				    ATOM_DEVICE_CRT1_SUPPORT))
723b7e1c893Smrg		return FALSE;
724209ff23fSmrg	} else
725209ff23fSmrg	    return FALSE;
726209ff23fSmrg    }
727209ff23fSmrg
728209ff23fSmrg    /* check LVDS table */
729b7e1c893Smrg    /* IGP can be mobile or desktop so check the connectors */
730b7e1c893Smrg    if (info->IsMobility || info->IsIGP) {
731209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x40);
732209ff23fSmrg	if (offset) {
733209ff23fSmrg	    info->BiosConnector[4].valid = TRUE;
734209ff23fSmrg	    info->BiosConnector[4].ConnectorType = CONNECTOR_LVDS;
735209ff23fSmrg	    info->BiosConnector[4].ddc_i2c.valid = FALSE;
736209ff23fSmrg
737b7e1c893Smrg	    info->BiosConnector[4].devices = ATOM_DEVICE_LCD1_SUPPORT;
738b7e1c893Smrg	    if (!radeon_add_encoder(pScrn,
739b7e1c893Smrg				    radeon_get_encoder_id_from_supported_device(pScrn,
740b7e1c893Smrg										ATOM_DEVICE_LCD1_SUPPORT,
741b7e1c893Smrg										0),
742b7e1c893Smrg				    ATOM_DEVICE_LCD1_SUPPORT))
743b7e1c893Smrg		return FALSE;
744b7e1c893Smrg
745209ff23fSmrg	    tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x42);
746209ff23fSmrg	    if (tmp) {
747209ff23fSmrg		tmp0 = RADEON_BIOS16(tmp + 0x15);
748209ff23fSmrg		if (tmp0) {
749209ff23fSmrg		    tmp1 = RADEON_BIOS8(tmp0+2) & 0x07;
750209ff23fSmrg		    if (tmp1) {
751209ff23fSmrg			DDCType	= tmp1;
752209ff23fSmrg			switch (DDCType) {
753b7e1c893Smrg			case DDC_NONE_DETECTED:
754b7e1c893Smrg			    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No DDC for LCD\n");
755b7e1c893Smrg			    break;
756209ff23fSmrg			case DDC_MONID:
757209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID);
758209ff23fSmrg			    break;
759209ff23fSmrg			case DDC_DVI:
760209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
761209ff23fSmrg			    break;
762209ff23fSmrg			case DDC_VGA:
763209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
764209ff23fSmrg			    break;
765209ff23fSmrg			case DDC_CRT2:
766209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
767209ff23fSmrg			    break;
768209ff23fSmrg			case DDC_LCD:
769209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_LCD_GPIO_MASK);
770b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.mask_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
771b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.mask_data_mask = RADEON_BIOS32(tmp0 + 0x07);
772b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.a_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
773b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.a_data_mask = RADEON_BIOS32(tmp0 + 0x07);
774209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.put_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
775209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.put_data_mask = RADEON_BIOS32(tmp0 + 0x07);
776209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.get_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
777209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.get_data_mask = RADEON_BIOS32(tmp0 + 0x07);
778209ff23fSmrg			    break;
779209ff23fSmrg			case DDC_GPIO:
780209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_MDGPIO_EN_REG);
781b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.mask_clk_mask =  RADEON_BIOS32(tmp0 + 0x03);
782b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.mask_data_mask = RADEON_BIOS32(tmp0 + 0x07);
783b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.a_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
784b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.a_data_mask = RADEON_BIOS32(tmp0 + 0x07);
785209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.put_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
786209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.put_data_mask = RADEON_BIOS32(tmp0 + 0x07);
787209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.get_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
788209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.get_data_mask = RADEON_BIOS32(tmp0 + 0x07);
789209ff23fSmrg			    break;
790209ff23fSmrg			default:
791209ff23fSmrg			    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown DDC Type: %d\n", DDCType);
792209ff23fSmrg			    break;
793209ff23fSmrg			}
794209ff23fSmrg			xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "LCD DDC Info Table found!\n");
795209ff23fSmrg		    }
796209ff23fSmrg		}
797b7e1c893Smrg	    } else
798209ff23fSmrg		info->BiosConnector[4].ddc_i2c.valid = FALSE;
799209ff23fSmrg	}
800209ff23fSmrg    }
801209ff23fSmrg
802209ff23fSmrg    /* check TV table */
803209ff23fSmrg    if (info->InternalTVOut) {
804209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32);
805209ff23fSmrg	if (offset) {
806209ff23fSmrg	    if (RADEON_BIOS8(offset + 6) == 'T') {
807209ff23fSmrg		info->BiosConnector[5].valid = TRUE;
808209ff23fSmrg		/* assume s-video for now */
809209ff23fSmrg		info->BiosConnector[5].ConnectorType = CONNECTOR_STV;
810b7e1c893Smrg		info->BiosConnector[5].load_detection = FALSE;
811209ff23fSmrg		info->BiosConnector[5].ddc_i2c.valid = FALSE;
812b7e1c893Smrg		info->BiosConnector[5].devices = ATOM_DEVICE_TV1_SUPPORT;
813b7e1c893Smrg		if (!radeon_add_encoder(pScrn,
814b7e1c893Smrg					radeon_get_encoder_id_from_supported_device(pScrn,
815b7e1c893Smrg										    ATOM_DEVICE_TV1_SUPPORT,
816b7e1c893Smrg										    2),
817b7e1c893Smrg					ATOM_DEVICE_TV1_SUPPORT))
818b7e1c893Smrg		    return FALSE;
819209ff23fSmrg	    }
820209ff23fSmrg	}
821209ff23fSmrg    }
822209ff23fSmrg
823209ff23fSmrg    return TRUE;
824209ff23fSmrg}
825209ff23fSmrg
826209ff23fSmrgBool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
827209ff23fSmrg{
828209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
829209ff23fSmrg
830209ff23fSmrg    if(!info->VBIOS) return FALSE;
831209ff23fSmrg
832209ff23fSmrg    if (info->IsAtomBios)
833209ff23fSmrg	return RADEONGetATOMConnectorInfoFromBIOS(pScrn);
834209ff23fSmrg    else
835209ff23fSmrg	return RADEONGetLegacyConnectorInfoFromBIOS(pScrn);
836209ff23fSmrg}
837209ff23fSmrg
838209ff23fSmrgBool RADEONGetTVInfoFromBIOS (xf86OutputPtr output) {
839209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
840209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
841209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
842b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
843209ff23fSmrg    int offset, refclk, stds;
844209ff23fSmrg
845209ff23fSmrg    if (!info->VBIOS) return FALSE;
846209ff23fSmrg
847b7e1c893Smrg    if (info->IsAtomBios)
848209ff23fSmrg        return RADEONGetATOMTVInfo(output);
849b7e1c893Smrg    else {
850209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32);
851209ff23fSmrg	if (offset) {
852209ff23fSmrg	    if (RADEON_BIOS8(offset + 6) == 'T') {
853209ff23fSmrg		switch (RADEON_BIOS8(offset + 7) & 0xf) {
854209ff23fSmrg		case 1:
855b7e1c893Smrg		    tvout->default_tvStd = TV_STD_NTSC;
856209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC\n");
857209ff23fSmrg		    break;
858209ff23fSmrg		case 2:
859b7e1c893Smrg		    tvout->default_tvStd = TV_STD_PAL;
860209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL\n");
861209ff23fSmrg		    break;
862209ff23fSmrg		case 3:
863b7e1c893Smrg		    tvout->default_tvStd = TV_STD_PAL_M;
864209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-M\n");
865209ff23fSmrg		    break;
866209ff23fSmrg		case 4:
867b7e1c893Smrg		    tvout->default_tvStd = TV_STD_PAL_60;
868209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-60\n");
869209ff23fSmrg		    break;
870209ff23fSmrg		case 5:
871b7e1c893Smrg		    tvout->default_tvStd = TV_STD_NTSC_J;
872209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC-J\n");
873209ff23fSmrg		    break;
874209ff23fSmrg		case 6:
875b7e1c893Smrg		    tvout->default_tvStd = TV_STD_SCART_PAL;
876209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: SCART-PAL\n");
877209ff23fSmrg		    break;
878209ff23fSmrg		default:
879b7e1c893Smrg		    tvout->default_tvStd = TV_STD_NTSC;
880209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Unknown TV standard; defaulting to NTSC\n");
881209ff23fSmrg		    break;
882209ff23fSmrg		}
883b7e1c893Smrg		tvout->tvStd = tvout->default_tvStd;
884209ff23fSmrg
885209ff23fSmrg		refclk = (RADEON_BIOS8(offset + 9) >> 2) & 0x3;
886209ff23fSmrg		if (refclk == 0)
887b7e1c893Smrg		    tvout->TVRefClk = 29.498928713; /* MHz */
888209ff23fSmrg		else if (refclk == 1)
889b7e1c893Smrg		    tvout->TVRefClk = 28.636360000;
890209ff23fSmrg		else if (refclk == 2)
891b7e1c893Smrg		    tvout->TVRefClk = 14.318180000;
892209ff23fSmrg		else if (refclk == 3)
893b7e1c893Smrg		    tvout->TVRefClk = 27.000000000;
894209ff23fSmrg
895b7e1c893Smrg		tvout->SupportedTVStds = tvout->default_tvStd;
896209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standards supported by chip: ");
897209ff23fSmrg		stds = RADEON_BIOS8(offset + 10) & 0x1f;
898209ff23fSmrg		if (stds & TV_STD_NTSC) {
899b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_NTSC;
900209ff23fSmrg		    ErrorF("NTSC ");
901209ff23fSmrg		}
902209ff23fSmrg		if (stds & TV_STD_PAL) {
903b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_PAL;
904209ff23fSmrg		    ErrorF("PAL ");
905209ff23fSmrg		}
906209ff23fSmrg		if (stds & TV_STD_PAL_M) {
907b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_PAL_M;
908209ff23fSmrg		    ErrorF("PAL-M ");
909209ff23fSmrg		}
910209ff23fSmrg		if (stds & TV_STD_PAL_60) {
911b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_PAL_60;
912209ff23fSmrg		    ErrorF("PAL-60 ");
913209ff23fSmrg		}
914209ff23fSmrg		if (stds & TV_STD_NTSC_J) {
915b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_NTSC_J;
916209ff23fSmrg		    ErrorF("NTSC-J ");
917209ff23fSmrg		}
918209ff23fSmrg		if (stds & TV_STD_SCART_PAL) {
919b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_SCART_PAL;
920209ff23fSmrg		    ErrorF("SCART-PAL");
921209ff23fSmrg		}
922209ff23fSmrg		ErrorF("\n");
923209ff23fSmrg
924209ff23fSmrg		return TRUE;
925209ff23fSmrg	    }
926209ff23fSmrg	}
927209ff23fSmrg    }
928209ff23fSmrg    return FALSE;
929209ff23fSmrg}
930209ff23fSmrg
931209ff23fSmrg/* Read PLL parameters from BIOS block.  Default to typical values if there
932209ff23fSmrg   is no BIOS. */
933209ff23fSmrgBool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn)
934209ff23fSmrg{
935209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
936209ff23fSmrg    RADEONPLLPtr pll = &info->pll;
937209ff23fSmrg    uint16_t pll_info_block;
938209ff23fSmrg
939209ff23fSmrg    if (!info->VBIOS) {
940209ff23fSmrg	return FALSE;
941209ff23fSmrg    } else {
942209ff23fSmrg	if (info->IsAtomBios) {
943209ff23fSmrg	    pll_info_block = RADEON_BIOS16 (info->MasterDataStart + 12);
944209ff23fSmrg
945209ff23fSmrg	    pll->reference_freq = RADEON_BIOS16 (pll_info_block + 82);
946209ff23fSmrg	    pll->reference_div = 0; /* Need to derive from existing setting
947209ff23fSmrg					or use a new algorithm to calculate
948209ff23fSmrg					from min_input and max_input
949209ff23fSmrg				     */
950209ff23fSmrg	    pll->pll_out_min = RADEON_BIOS16 (pll_info_block + 78);
951209ff23fSmrg	    pll->pll_out_max = RADEON_BIOS32 (pll_info_block + 32);
952209ff23fSmrg
953209ff23fSmrg	    if (pll->pll_out_min == 0) {
954209ff23fSmrg		if (IS_AVIVO_VARIANT)
955209ff23fSmrg		    pll->pll_out_min = 64800;
956209ff23fSmrg		else
957209ff23fSmrg		    pll->pll_out_min = 20000;
958209ff23fSmrg	    }
959209ff23fSmrg
960209ff23fSmrg	    pll->pll_in_min = RADEON_BIOS16 (pll_info_block + 74);
961209ff23fSmrg	    pll->pll_in_max = RADEON_BIOS16 (pll_info_block + 76);
962209ff23fSmrg
963209ff23fSmrg	    pll->xclk = RADEON_BIOS16 (pll_info_block + 72);
964209ff23fSmrg
965209ff23fSmrg	    info->sclk = RADEON_BIOS32(pll_info_block + 8) / 100.0;
966209ff23fSmrg	    info->mclk = RADEON_BIOS32(pll_info_block + 12) / 100.0;
967209ff23fSmrg	} else {
968209ff23fSmrg	    int rev;
969209ff23fSmrg
970209ff23fSmrg	    pll_info_block = RADEON_BIOS16 (info->ROMHeaderStart + 0x30);
971209ff23fSmrg
972209ff23fSmrg	    rev = RADEON_BIOS8(pll_info_block);
973209ff23fSmrg
974209ff23fSmrg	    pll->reference_freq = RADEON_BIOS16 (pll_info_block + 0x0e);
975209ff23fSmrg	    pll->reference_div = RADEON_BIOS16 (pll_info_block + 0x10);
976209ff23fSmrg	    pll->pll_out_min = RADEON_BIOS32 (pll_info_block + 0x12);
977209ff23fSmrg	    pll->pll_out_max = RADEON_BIOS32 (pll_info_block + 0x16);
978209ff23fSmrg
979209ff23fSmrg	    if (rev > 9) {
980209ff23fSmrg		pll->pll_in_min = RADEON_BIOS32(pll_info_block + 0x36);
981209ff23fSmrg		pll->pll_in_max = RADEON_BIOS32(pll_info_block + 0x3a);
982209ff23fSmrg	    } else {
983209ff23fSmrg		pll->pll_in_min = 40;
984209ff23fSmrg		pll->pll_in_max = 500;
985209ff23fSmrg	    }
986209ff23fSmrg
987209ff23fSmrg	    pll->xclk = RADEON_BIOS16(pll_info_block + 0x08);
988209ff23fSmrg
989b7e1c893Smrg	    info->sclk = RADEON_BIOS16(pll_info_block + 10) / 100.0;
990b7e1c893Smrg	    info->mclk = RADEON_BIOS16(pll_info_block + 8) / 100.0;
991209ff23fSmrg	}
992209ff23fSmrg
993209ff23fSmrg	if (info->sclk == 0) info->sclk = 200;
994209ff23fSmrg	if (info->mclk == 0) info->mclk = 200;
995209ff23fSmrg    }
996209ff23fSmrg
997209ff23fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ref_freq: %d, min_out_pll: %u, "
998209ff23fSmrg	       "max_out_pll: %u, min_in_pll: %u, max_in_pll: %u, xclk: %d, "
999209ff23fSmrg	       "sclk: %f, mclk: %f\n",
1000209ff23fSmrg	       pll->reference_freq, (unsigned)pll->pll_out_min,
1001209ff23fSmrg	       (unsigned)pll->pll_out_max, (unsigned)pll->pll_in_min,
1002209ff23fSmrg	       (unsigned)pll->pll_in_max, pll->xclk, info->sclk, info->mclk);
1003209ff23fSmrg
1004209ff23fSmrg    return TRUE;
1005209ff23fSmrg}
1006209ff23fSmrg
1007b7e1c893SmrgBool RADEONGetDAC2InfoFromBIOS (ScrnInfoPtr pScrn, radeon_tvdac_ptr tvdac)
1008209ff23fSmrg{
1009209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1010209ff23fSmrg    int offset, rev, bg, dac;
1011209ff23fSmrg
1012209ff23fSmrg    if (!info->VBIOS) return FALSE;
1013209ff23fSmrg
1014209ff23fSmrg    if (xf86ReturnOptValBool(info->Options, OPTION_DEFAULT_TVDAC_ADJ, FALSE))
1015209ff23fSmrg	return FALSE;
1016209ff23fSmrg
1017209ff23fSmrg    if (info->IsAtomBios) {
1018209ff23fSmrg	/* not implemented yet */
1019209ff23fSmrg	return FALSE;
1020209ff23fSmrg    } else {
1021209ff23fSmrg	/* first check TV table */
1022209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32);
1023209ff23fSmrg        if (offset) {
1024209ff23fSmrg	    rev = RADEON_BIOS8(offset + 0x3);
1025209ff23fSmrg	    if (rev > 4) {
1026209ff23fSmrg		bg = RADEON_BIOS8(offset + 0xc) & 0xf;
1027209ff23fSmrg		dac = RADEON_BIOS8(offset + 0xd) & 0xf;
1028b7e1c893Smrg		tvdac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1029209ff23fSmrg
1030209ff23fSmrg		bg = RADEON_BIOS8(offset + 0xe) & 0xf;
1031209ff23fSmrg		dac = RADEON_BIOS8(offset + 0xf) & 0xf;
1032b7e1c893Smrg		tvdac->pal_tvdac_adj = (bg << 16) | (dac << 20);
1033209ff23fSmrg
1034209ff23fSmrg		bg = RADEON_BIOS8(offset + 0x10) & 0xf;
1035209ff23fSmrg		dac = RADEON_BIOS8(offset + 0x11) & 0xf;
1036b7e1c893Smrg		tvdac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
1037209ff23fSmrg
1038209ff23fSmrg		return TRUE;
1039209ff23fSmrg	    } else if (rev > 1) {
1040209ff23fSmrg		bg = RADEON_BIOS8(offset + 0xc) & 0xf;
1041209ff23fSmrg		dac = (RADEON_BIOS8(offset + 0xc) >> 4) & 0xf;
1042b7e1c893Smrg		tvdac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1043209ff23fSmrg
1044209ff23fSmrg		bg = RADEON_BIOS8(offset + 0xd) & 0xf;
1045209ff23fSmrg		dac = (RADEON_BIOS8(offset + 0xd) >> 4) & 0xf;
1046b7e1c893Smrg		tvdac->pal_tvdac_adj = (bg << 16) | (dac << 20);
1047209ff23fSmrg
1048209ff23fSmrg		bg = RADEON_BIOS8(offset + 0xe) & 0xf;
1049209ff23fSmrg		dac = (RADEON_BIOS8(offset + 0xe) >> 4) & 0xf;
1050b7e1c893Smrg		tvdac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
1051209ff23fSmrg
1052209ff23fSmrg		return TRUE;
1053209ff23fSmrg	    }
1054209ff23fSmrg	}
1055209ff23fSmrg	/* then check CRT table */
1056209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x60);
1057209ff23fSmrg        if (offset) {
1058209ff23fSmrg	    rev = RADEON_BIOS8(offset) & 0x3;
1059209ff23fSmrg	    if (rev < 2) {
1060209ff23fSmrg		bg = RADEON_BIOS8(offset + 0x3) & 0xf;
1061209ff23fSmrg		dac = (RADEON_BIOS8(offset + 0x3) >> 4) & 0xf;
1062b7e1c893Smrg		tvdac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1063b7e1c893Smrg		tvdac->pal_tvdac_adj = tvdac->ps2_tvdac_adj;
1064b7e1c893Smrg		tvdac->ntsc_tvdac_adj = tvdac->ps2_tvdac_adj;
1065209ff23fSmrg
1066209ff23fSmrg		return TRUE;
1067209ff23fSmrg	    } else {
1068209ff23fSmrg		bg = RADEON_BIOS8(offset + 0x4) & 0xf;
1069209ff23fSmrg		dac = RADEON_BIOS8(offset + 0x5) & 0xf;
1070b7e1c893Smrg		tvdac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1071b7e1c893Smrg		tvdac->pal_tvdac_adj = tvdac->ps2_tvdac_adj;
1072b7e1c893Smrg		tvdac->ntsc_tvdac_adj = tvdac->ps2_tvdac_adj;
1073209ff23fSmrg
1074209ff23fSmrg		return TRUE;
1075209ff23fSmrg	    }
1076209ff23fSmrg	}
1077209ff23fSmrg    }
1078209ff23fSmrg
1079209ff23fSmrg    return FALSE;
1080209ff23fSmrg}
1081209ff23fSmrg
1082b7e1c893SmrgBool
1083b7e1c893SmrgRADEONGetLVDSInfoFromBIOS(ScrnInfoPtr pScrn, radeon_lvds_ptr lvds)
1084209ff23fSmrg{
1085209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1086b7e1c893Smrg    radeon_native_mode_ptr native_mode = &lvds->native_mode;
1087209ff23fSmrg    unsigned long tmp, i;
1088209ff23fSmrg
1089b7e1c893Smrg    if (!info->VBIOS)
1090b7e1c893Smrg	return FALSE;
1091209ff23fSmrg
1092b7e1c893Smrg    if (!info->IsAtomBios) {
1093209ff23fSmrg	tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x40);
1094209ff23fSmrg
1095209ff23fSmrg	if (!tmp) {
1096209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1097209ff23fSmrg		       "No Panel Info Table found in BIOS!\n");
1098209ff23fSmrg	    return FALSE;
1099209ff23fSmrg	} else {
1100209ff23fSmrg	    char  stmp[30];
1101209ff23fSmrg	    int   tmp0;
1102209ff23fSmrg
1103209ff23fSmrg	    for (i = 0; i < 24; i++)
1104209ff23fSmrg	    stmp[i] = RADEON_BIOS8(tmp+i+1);
1105209ff23fSmrg	    stmp[24] = 0;
1106209ff23fSmrg
1107209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1108209ff23fSmrg		       "Panel ID string: %s\n", stmp);
1109209ff23fSmrg
1110b7e1c893Smrg	    native_mode->PanelXRes = RADEON_BIOS16(tmp+25);
1111b7e1c893Smrg	    native_mode->PanelYRes = RADEON_BIOS16(tmp+27);
1112209ff23fSmrg	    xf86DrvMsg(0, X_INFO, "Panel Size from BIOS: %dx%d\n",
1113b7e1c893Smrg		       native_mode->PanelXRes, native_mode->PanelYRes);
1114b7e1c893Smrg
1115b7e1c893Smrg	    lvds->PanelPwrDly = RADEON_BIOS16(tmp+44);
1116b7e1c893Smrg	    if (lvds->PanelPwrDly > 2000 || lvds->PanelPwrDly < 0)
1117b7e1c893Smrg		lvds->PanelPwrDly = 2000;
1118209ff23fSmrg
1119209ff23fSmrg	    /* some panels only work well with certain divider combinations.
1120209ff23fSmrg	     */
1121209ff23fSmrg	    info->RefDivider = RADEON_BIOS16(tmp+46);
1122209ff23fSmrg	    info->PostDivider = RADEON_BIOS8(tmp+48);
1123209ff23fSmrg	    info->FeedbackDivider = RADEON_BIOS16(tmp+49);
1124209ff23fSmrg	    if ((info->RefDivider != 0) &&
1125209ff23fSmrg		(info->FeedbackDivider > 3)) {
1126209ff23fSmrg		info->UseBiosDividers = TRUE;
1127209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1128209ff23fSmrg			   "BIOS provided dividers will be used.\n");
1129209ff23fSmrg	    }
1130209ff23fSmrg
1131209ff23fSmrg	    /* We don't use a while loop here just in case we have a corrupted BIOS image.
1132209ff23fSmrg	       The max number of table entries is 23 at present, but may grow in future.
1133209ff23fSmrg	       To ensure it works with future revisions we loop it to 32.
1134209ff23fSmrg	    */
1135209ff23fSmrg	    for (i = 0; i < 32; i++) {
1136209ff23fSmrg		tmp0 = RADEON_BIOS16(tmp+64+i*2);
1137209ff23fSmrg		if (tmp0 == 0) break;
1138b7e1c893Smrg		if ((RADEON_BIOS16(tmp0) == native_mode->PanelXRes) &&
1139b7e1c893Smrg		    (RADEON_BIOS16(tmp0+2) == native_mode->PanelYRes)) {
1140b7e1c893Smrg		    native_mode->HBlank     = (RADEON_BIOS16(tmp0+17) -
1141b7e1c893Smrg					       RADEON_BIOS16(tmp0+19)) * 8;
1142b7e1c893Smrg		    native_mode->HOverPlus  = (RADEON_BIOS16(tmp0+21) -
1143b7e1c893Smrg					       RADEON_BIOS16(tmp0+19) - 1) * 8;
1144b7e1c893Smrg		    native_mode->HSyncWidth = RADEON_BIOS8(tmp0+23) * 8;
1145b7e1c893Smrg		    native_mode->VBlank     = (RADEON_BIOS16(tmp0+24) -
1146b7e1c893Smrg					       RADEON_BIOS16(tmp0+26));
1147b7e1c893Smrg		    native_mode->VOverPlus  = ((RADEON_BIOS16(tmp0+28) & 0x7ff) -
1148b7e1c893Smrg					       RADEON_BIOS16(tmp0+26));
1149b7e1c893Smrg		    native_mode->VSyncWidth = ((RADEON_BIOS16(tmp0+28) & 0xf800) >> 11);
1150b7e1c893Smrg		    native_mode->DotClock   = RADEON_BIOS16(tmp0+9) * 10;
1151b7e1c893Smrg		    native_mode->Flags = 0;
1152209ff23fSmrg		}
1153209ff23fSmrg	    }
1154209ff23fSmrg	}
1155209ff23fSmrg
1156b7e1c893Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1157b7e1c893Smrg		   "LVDS Info:\n"
1158b7e1c893Smrg		   "XRes: %d, YRes: %d, DotClock: %d\n"
1159b7e1c893Smrg		   "HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n"
1160b7e1c893Smrg		   "VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n",
1161b7e1c893Smrg		   native_mode->PanelXRes, native_mode->PanelYRes, native_mode->DotClock,
1162b7e1c893Smrg		   native_mode->HBlank, native_mode->HOverPlus, native_mode->HSyncWidth,
1163b7e1c893Smrg		   native_mode->VBlank, native_mode->VOverPlus, native_mode->VSyncWidth);
1164209ff23fSmrg
1165b7e1c893Smrg	return TRUE;
1166b7e1c893Smrg    }
1167b7e1c893Smrg    return FALSE;
1168209ff23fSmrg}
1169209ff23fSmrg
1170b7e1c893Smrgxf86MonPtr RADEONGetHardCodedEDIDFromBIOS (xf86OutputPtr output)
1171209ff23fSmrg{
1172209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1173b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1174209ff23fSmrg    unsigned long tmp;
1175b7e1c893Smrg    unsigned char edid[256];
1176b7e1c893Smrg    xf86MonPtr mon = NULL;
1177209ff23fSmrg
1178b7e1c893Smrg    if (!info->VBIOS)
1179b7e1c893Smrg	return mon;
1180209ff23fSmrg
1181b7e1c893Smrg    if (!info->IsAtomBios) {
1182b7e1c893Smrg	tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x4c);
1183b7e1c893Smrg	if (tmp) {
1184b7e1c893Smrg	    memcpy(edid, (unsigned char*)(info->VBIOS + tmp), 256);
1185b7e1c893Smrg	    if (edid[1] == 0xff)
1186b7e1c893Smrg		mon = xf86InterpretEDID(output->scrn->scrnIndex, edid);
1187209ff23fSmrg	}
1188209ff23fSmrg    }
1189b7e1c893Smrg
1190b7e1c893Smrg    return mon;
1191209ff23fSmrg}
1192209ff23fSmrg
1193b7e1c893SmrgBool RADEONGetTMDSInfoFromBIOS (ScrnInfoPtr pScrn, radeon_tmds_ptr tmds)
1194209ff23fSmrg{
1195209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1196209ff23fSmrg    uint32_t tmp, maxfreq;
1197209ff23fSmrg    int i, n;
1198209ff23fSmrg
1199209ff23fSmrg    if (!info->VBIOS) return FALSE;
1200209ff23fSmrg
1201209ff23fSmrg    if (info->IsAtomBios) {
1202209ff23fSmrg	if((tmp = RADEON_BIOS16 (info->MasterDataStart + 18))) {
1203209ff23fSmrg
1204209ff23fSmrg	    maxfreq = RADEON_BIOS16(tmp+4);
1205b7e1c893Smrg
1206209ff23fSmrg	    for (i=0; i<4; i++) {
1207b7e1c893Smrg		tmds->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*6+6);
1208209ff23fSmrg		/* This assumes each field in TMDS_PLL has 6 bit as in R300/R420 */
1209b7e1c893Smrg		tmds->tmds_pll[i].value = ((RADEON_BIOS8(tmp+i*6+8) & 0x3f) |
1210209ff23fSmrg					   ((RADEON_BIOS8(tmp+i*6+10) & 0x3f)<<6) |
1211209ff23fSmrg					   ((RADEON_BIOS8(tmp+i*6+9) & 0xf)<<12) |
1212209ff23fSmrg					   ((RADEON_BIOS8(tmp+i*6+11) & 0xf)<<16));
1213b7e1c893Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1214b7e1c893Smrg			   "TMDS PLL from BIOS: %u %x\n",
1215b7e1c893Smrg			   (unsigned)tmds->tmds_pll[i].freq,
1216b7e1c893Smrg			   (unsigned)tmds->tmds_pll[i].value);
1217b7e1c893Smrg
1218b7e1c893Smrg		if (maxfreq == tmds->tmds_pll[i].freq) {
1219b7e1c893Smrg		    tmds->tmds_pll[i].freq = 0xffffffff;
1220209ff23fSmrg		    break;
1221209ff23fSmrg		}
1222209ff23fSmrg	    }
1223209ff23fSmrg	    return TRUE;
1224209ff23fSmrg	}
1225209ff23fSmrg    } else {
1226209ff23fSmrg
1227209ff23fSmrg	tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x34);
1228209ff23fSmrg	if (tmp) {
1229209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1230209ff23fSmrg		       "DFP table revision: %d\n", RADEON_BIOS8(tmp));
1231209ff23fSmrg	    if (RADEON_BIOS8(tmp) == 3) {
1232209ff23fSmrg		n = RADEON_BIOS8(tmp + 5) + 1;
1233209ff23fSmrg		if (n > 4) n = 4;
1234209ff23fSmrg		for (i=0; i<n; i++) {
1235b7e1c893Smrg		    tmds->tmds_pll[i].value = RADEON_BIOS32(tmp+i*10+0x08);
1236b7e1c893Smrg		    tmds->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*10+0x10);
1237209ff23fSmrg		}
1238209ff23fSmrg		return TRUE;
1239209ff23fSmrg	    } else if (RADEON_BIOS8(tmp) == 4) {
1240209ff23fSmrg	        int stride = 0;
1241209ff23fSmrg		n = RADEON_BIOS8(tmp + 5) + 1;
1242209ff23fSmrg		if (n > 4) n = 4;
1243209ff23fSmrg		for (i=0; i<n; i++) {
1244b7e1c893Smrg		    tmds->tmds_pll[i].value = RADEON_BIOS32(tmp+stride+0x08);
1245b7e1c893Smrg		    tmds->tmds_pll[i].freq = RADEON_BIOS16(tmp+stride+0x10);
1246209ff23fSmrg		    if (i == 0) stride += 10;
1247209ff23fSmrg		    else stride += 6;
1248209ff23fSmrg		}
1249209ff23fSmrg		return TRUE;
1250209ff23fSmrg	    }
1251209ff23fSmrg	}
1252209ff23fSmrg    }
1253209ff23fSmrg    return FALSE;
1254209ff23fSmrg}
1255209ff23fSmrg
1256b7e1c893Smrgstatic RADEONI2CBusRec
1257b7e1c893SmrgRADEONLookupI2CBlock(ScrnInfoPtr pScrn, int id)
1258b7e1c893Smrg{
1259b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1260b7e1c893Smrg    int offset, blocks, i;
1261b7e1c893Smrg    RADEONI2CBusRec i2c;
1262b7e1c893Smrg
1263b7e1c893Smrg    memset(&i2c, 0, sizeof(RADEONI2CBusRec));
1264b7e1c893Smrg    i2c.valid = FALSE;
1265b7e1c893Smrg
1266b7e1c893Smrg    offset = RADEON_BIOS16(info->ROMHeaderStart + 0x70);
1267b7e1c893Smrg    if (offset) {
1268b7e1c893Smrg	blocks = RADEON_BIOS8(offset + 2);
1269b7e1c893Smrg	for (i = 0; i < blocks; i++) {
1270b7e1c893Smrg	    int i2c_id = RADEON_BIOS8(offset + 3 + (i * 5) + 0);
1271b7e1c893Smrg	    if (id == i2c_id) {
1272b7e1c893Smrg		int reg = RADEON_BIOS16(offset + 3 + (i * 5) + 1) * 4;
1273b7e1c893Smrg		int clock_shift = RADEON_BIOS8(offset + 3 + (i * 5) + 3);
1274b7e1c893Smrg		int data_shift = RADEON_BIOS8(offset + 3 + (i * 5) + 4);
1275b7e1c893Smrg
1276b7e1c893Smrg		i2c.mask_clk_mask = (1 << clock_shift);
1277b7e1c893Smrg		i2c.mask_data_mask = (1 << data_shift);
1278b7e1c893Smrg		i2c.a_clk_mask = (1 << clock_shift);
1279b7e1c893Smrg		i2c.a_data_mask = (1 << data_shift);
1280b7e1c893Smrg		i2c.put_clk_mask = (1 << clock_shift);
1281b7e1c893Smrg		i2c.put_data_mask = (1 << data_shift);
1282b7e1c893Smrg		i2c.get_clk_mask = (1 << clock_shift);
1283b7e1c893Smrg		i2c.get_data_mask = (1 << data_shift);
1284b7e1c893Smrg		i2c.mask_clk_reg = reg;
1285b7e1c893Smrg		i2c.mask_data_reg = reg;
1286b7e1c893Smrg		i2c.a_clk_reg = reg;
1287b7e1c893Smrg		i2c.a_data_reg = reg;
1288b7e1c893Smrg		i2c.put_clk_reg = reg;
1289b7e1c893Smrg		i2c.put_data_reg = reg;
1290b7e1c893Smrg		i2c.get_clk_reg = reg;
1291b7e1c893Smrg		i2c.get_data_reg = reg;
1292b7e1c893Smrg		i2c.valid = TRUE;
1293b7e1c893Smrg		break;
1294b7e1c893Smrg	    }
1295b7e1c893Smrg	}
1296b7e1c893Smrg    }
1297b7e1c893Smrg    return i2c;
1298b7e1c893Smrg}
1299b7e1c893Smrg
1300b7e1c893SmrgBool RADEONGetExtTMDSInfoFromBIOS (ScrnInfoPtr pScrn, radeon_dvo_ptr dvo)
1301209ff23fSmrg{
1302209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1303209ff23fSmrg    int offset, table_start, max_freq, gpio_reg, flags;
1304209ff23fSmrg
1305b7e1c893Smrg    if (!info->VBIOS)
1306b7e1c893Smrg	return FALSE;
1307209ff23fSmrg
1308b7e1c893Smrg    if (info->IsAtomBios)
1309209ff23fSmrg	return FALSE;
1310b7e1c893Smrg    else if (info->IsIGP) {
1311b7e1c893Smrg	/* RS4xx TMDS stuff is in the mobile table */
1312b7e1c893Smrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x42);
1313b7e1c893Smrg	if (offset) {
1314b7e1c893Smrg	    int rev = RADEON_BIOS8(offset);
1315b7e1c893Smrg	    if (rev >= 6) {
1316b7e1c893Smrg		offset = RADEON_BIOS16(offset + 0x17);
1317b7e1c893Smrg		if (offset) {
1318b7e1c893Smrg		    offset = RADEON_BIOS16(offset + 2);
1319b7e1c893Smrg		    rev = RADEON_BIOS8(offset);
1320b7e1c893Smrg		    if (offset && (rev > 1)) {
1321b7e1c893Smrg			int blocks = RADEON_BIOS8(offset + 3);
1322b7e1c893Smrg			int index = offset + 4;
1323b7e1c893Smrg			dvo->dvo_i2c.valid = FALSE;
1324b7e1c893Smrg			while (blocks > 0) {
1325b7e1c893Smrg			    int id = RADEON_BIOS16(index);
1326b7e1c893Smrg			    index += 2;
1327b7e1c893Smrg			    switch (id >> 13) {
1328b7e1c893Smrg			    case 0:
1329b7e1c893Smrg				index += 6;
1330b7e1c893Smrg				break;
1331b7e1c893Smrg			    case 2:
1332b7e1c893Smrg				index += 10;
1333b7e1c893Smrg				break;
1334b7e1c893Smrg			    case 3:
1335b7e1c893Smrg				index += 2;
1336b7e1c893Smrg				break;
1337b7e1c893Smrg			    case 4:
1338b7e1c893Smrg				index += 2;
1339b7e1c893Smrg				break;
1340b7e1c893Smrg			    case 6:
1341b7e1c893Smrg				dvo->dvo_i2c_slave_addr =
1342b7e1c893Smrg				    RADEON_BIOS16(index) & 0xff;
1343b7e1c893Smrg				index += 2;
1344b7e1c893Smrg				dvo->dvo_i2c =
1345b7e1c893Smrg				    RADEONLookupI2CBlock(pScrn, RADEON_BIOS8(index));
1346b7e1c893Smrg				return TRUE;
1347b7e1c893Smrg			    default:
1348b7e1c893Smrg				break;
1349b7e1c893Smrg			    }
1350b7e1c893Smrg			    blocks--;
1351b7e1c893Smrg			}
1352b7e1c893Smrg		    }
1353b7e1c893Smrg		}
1354b7e1c893Smrg	    }
1355b7e1c893Smrg	}
1356209ff23fSmrg    } else {
1357209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x58);
1358209ff23fSmrg	if (offset) {
1359209ff23fSmrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1360209ff23fSmrg			"External TMDS Table revision: %d\n",
1361209ff23fSmrg			RADEON_BIOS8(offset));
1362209ff23fSmrg	    table_start = offset+4;
1363209ff23fSmrg	    max_freq = RADEON_BIOS16(table_start);
1364b7e1c893Smrg	    dvo->dvo_i2c_slave_addr = RADEON_BIOS8(table_start+2);
1365b7e1c893Smrg	    dvo->dvo_i2c.valid = FALSE;
1366209ff23fSmrg	    gpio_reg = RADEON_BIOS8(table_start+3);
1367209ff23fSmrg	    if (gpio_reg == 1)
1368b7e1c893Smrg		dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID);
1369209ff23fSmrg	    else if (gpio_reg == 2)
1370b7e1c893Smrg		dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
1371209ff23fSmrg	    else if (gpio_reg == 3)
1372b7e1c893Smrg		dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
1373209ff23fSmrg	    else if (gpio_reg == 4)
1374b7e1c893Smrg		dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
1375b7e1c893Smrg	    else if (gpio_reg == 5) {
1376209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1377209ff23fSmrg			   "unsupported MM gpio_reg\n");
1378b7e1c893Smrg		return FALSE;
1379b7e1c893Smrg	    } else {
1380209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1381209ff23fSmrg			   "Unknown gpio reg: %d\n", gpio_reg);
1382209ff23fSmrg		return FALSE;
1383209ff23fSmrg	    }
1384209ff23fSmrg	    flags = RADEON_BIOS8(table_start+5);
1385b7e1c893Smrg	    dvo->dvo_duallink = flags & 0x01;
1386b7e1c893Smrg	    if (dvo->dvo_duallink) {
1387209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1388209ff23fSmrg			   "Duallink TMDS detected\n");
1389209ff23fSmrg	    }
1390209ff23fSmrg	    return TRUE;
1391209ff23fSmrg	}
1392209ff23fSmrg    }
1393209ff23fSmrg
1394209ff23fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1395209ff23fSmrg	       "No External TMDS Table found\n");
1396209ff23fSmrg
1397209ff23fSmrg    return FALSE;
1398209ff23fSmrg}
1399209ff23fSmrg
1400209ff23fSmrgBool RADEONInitExtTMDSInfoFromBIOS (xf86OutputPtr output)
1401209ff23fSmrg{
1402209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1403209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1404209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1405b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1406b7e1c893Smrg    radeon_dvo_ptr dvo = NULL;
1407209ff23fSmrg    int offset, index, id;
1408b7e1c893Smrg    uint32_t val, reg, and_mask, or_mask;
1409209ff23fSmrg
1410b7e1c893Smrg    if (radeon_encoder == NULL)
1411b7e1c893Smrg	return FALSE;
1412209ff23fSmrg
1413b7e1c893Smrg    dvo = (radeon_dvo_ptr)radeon_encoder->dev_priv;
1414b7e1c893Smrg
1415b7e1c893Smrg    if (dvo == NULL)
1416b7e1c893Smrg	return FALSE;
1417b7e1c893Smrg
1418b7e1c893Smrg    if (!info->VBIOS)
1419b7e1c893Smrg	return FALSE;
1420b7e1c893Smrg
1421b7e1c893Smrg    if (info->IsAtomBios)
1422209ff23fSmrg	return FALSE;
1423b7e1c893Smrg    else if (info->IsIGP) {
1424b7e1c893Smrg	/* RS4xx TMDS stuff is in the mobile table */
1425b7e1c893Smrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x42);
1426b7e1c893Smrg	if (offset) {
1427b7e1c893Smrg	    int rev = RADEON_BIOS8(offset);
1428b7e1c893Smrg	    if (rev >= 6) {
1429b7e1c893Smrg		offset = RADEON_BIOS16(offset + 0x17);
1430b7e1c893Smrg		if (offset) {
1431b7e1c893Smrg		    offset = RADEON_BIOS16(offset + 2);
1432b7e1c893Smrg		    rev = RADEON_BIOS8(offset);
1433b7e1c893Smrg		    if (offset && (rev > 1)) {
1434b7e1c893Smrg			int blocks = RADEON_BIOS8(offset + 3);
1435b7e1c893Smrg			index = offset + 4;
1436b7e1c893Smrg			while (blocks > 0) {
1437b7e1c893Smrg			    id = RADEON_BIOS16(index);
1438b7e1c893Smrg			    index += 2;
1439b7e1c893Smrg			    switch (id >> 13) {
1440b7e1c893Smrg			    case 0:
1441b7e1c893Smrg				reg = (id & 0x1fff) * 4;
1442b7e1c893Smrg				val = RADEON_BIOS32(index);
1443b7e1c893Smrg				index += 4;
1444b7e1c893Smrg				ErrorF("MMIO: 0x%x 0x%x\n",
1445b7e1c893Smrg				       (unsigned)reg, (unsigned)val);
1446b7e1c893Smrg				OUTREG(reg, val);
1447b7e1c893Smrg				break;
1448b7e1c893Smrg			    case 2:
1449b7e1c893Smrg				reg = (id & 0x1fff) * 4;
1450b7e1c893Smrg				and_mask = RADEON_BIOS32(index);
1451b7e1c893Smrg				index += 4;
1452b7e1c893Smrg				or_mask = RADEON_BIOS32(index);
1453b7e1c893Smrg				index += 4;
1454b7e1c893Smrg				ErrorF("MMIO mask: 0x%x 0x%x 0x%x\n",
1455b7e1c893Smrg				       (unsigned)reg, (unsigned)and_mask, (unsigned)or_mask);
1456b7e1c893Smrg				val = INREG(reg);
1457b7e1c893Smrg				val = (val & and_mask) | or_mask;
1458b7e1c893Smrg				OUTREG(reg, val);
1459b7e1c893Smrg				break;
1460b7e1c893Smrg			    case 3:
1461b7e1c893Smrg				val = RADEON_BIOS16(index);
1462b7e1c893Smrg				index += 2;
1463b7e1c893Smrg				ErrorF("delay: %u\n", (unsigned)val);
1464b7e1c893Smrg				usleep(val);
1465b7e1c893Smrg				break;
1466b7e1c893Smrg			    case 4:
1467b7e1c893Smrg				val = RADEON_BIOS16(index);
1468b7e1c893Smrg				index += 2;
1469b7e1c893Smrg				ErrorF("delay: %u\n", (unsigned)val * 1000);
1470b7e1c893Smrg				usleep(val * 1000);
1471b7e1c893Smrg				break;
1472b7e1c893Smrg			    case 6:
1473b7e1c893Smrg				index++;
1474b7e1c893Smrg				reg = RADEON_BIOS8(index);
1475b7e1c893Smrg				index++;
1476b7e1c893Smrg				val = RADEON_BIOS8(index);
1477b7e1c893Smrg				index++;
1478b7e1c893Smrg				ErrorF("i2c write: 0x%x, 0x%x\n", (unsigned)reg,
1479b7e1c893Smrg				       (unsigned)val);
1480b7e1c893Smrg				RADEONDVOWriteByte(dvo->DVOChip, reg, val);
1481b7e1c893Smrg				break;
1482b7e1c893Smrg			    default:
1483b7e1c893Smrg				ErrorF("unknown id %d\n", id>>13);
1484b7e1c893Smrg				return FALSE;
1485b7e1c893Smrg			    }
1486b7e1c893Smrg			    blocks--;
1487b7e1c893Smrg			}
1488b7e1c893Smrg			return TRUE;
1489b7e1c893Smrg		    }
1490b7e1c893Smrg		}
1491b7e1c893Smrg	    }
1492b7e1c893Smrg	}
1493209ff23fSmrg    } else {
1494209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x58);
1495209ff23fSmrg	if (offset) {
1496209ff23fSmrg	    index = offset+10;
1497209ff23fSmrg	    id = RADEON_BIOS16(index);
1498209ff23fSmrg	    while (id != 0xffff) {
1499209ff23fSmrg		index += 2;
1500209ff23fSmrg		switch(id >> 13) {
1501209ff23fSmrg		case 0:
1502b7e1c893Smrg		    reg = (id & 0x1fff) * 4;
1503209ff23fSmrg		    val = RADEON_BIOS32(index);
1504209ff23fSmrg		    index += 4;
1505b7e1c893Smrg		    ErrorF("MMIO: 0x%x 0x%x\n",
1506209ff23fSmrg			   (unsigned)reg, (unsigned)val);
1507b7e1c893Smrg		    OUTREG(reg, val);
1508209ff23fSmrg		    break;
1509209ff23fSmrg		case 2:
1510b7e1c893Smrg		    reg = (id & 0x1fff) * 4;
1511b7e1c893Smrg		    and_mask = RADEON_BIOS32(index);
1512209ff23fSmrg		    index += 4;
1513b7e1c893Smrg		    or_mask = RADEON_BIOS32(index);
1514209ff23fSmrg		    index += 4;
1515209ff23fSmrg		    val = INREG(reg);
1516b7e1c893Smrg		    val = (val & and_mask) | or_mask;
1517b7e1c893Smrg		    ErrorF("MMIO mask: 0x%x 0x%x 0x%x\n",
1518b7e1c893Smrg			   (unsigned)reg, (unsigned)and_mask, (unsigned)or_mask);
1519b7e1c893Smrg		    OUTREG(reg, val);
1520209ff23fSmrg		    break;
1521209ff23fSmrg		case 4:
1522209ff23fSmrg		    val = RADEON_BIOS16(index);
1523209ff23fSmrg		    index += 2;
1524209ff23fSmrg		    ErrorF("delay: %u\n", (unsigned)val);
1525209ff23fSmrg		    usleep(val);
1526209ff23fSmrg		    break;
1527209ff23fSmrg		case 5:
1528209ff23fSmrg		    reg = id & 0x1fff;
1529b7e1c893Smrg		    and_mask = RADEON_BIOS32(index);
1530209ff23fSmrg		    index += 4;
1531b7e1c893Smrg		    or_mask = RADEON_BIOS32(index);
1532209ff23fSmrg		    index += 4;
1533b7e1c893Smrg		    ErrorF("PLL mask: 0x%x 0x%x 0x%x\n",
1534b7e1c893Smrg			   (unsigned)reg, (unsigned)and_mask, (unsigned)or_mask);
1535b7e1c893Smrg		    val = INPLL(pScrn, reg);
1536b7e1c893Smrg		    val = (val & and_mask) | or_mask;
1537b7e1c893Smrg		    OUTPLL(pScrn, reg, val);
1538209ff23fSmrg		    break;
1539209ff23fSmrg		case 6:
1540209ff23fSmrg		    reg = id & 0x1fff;
1541209ff23fSmrg		    val = RADEON_BIOS8(index);
1542209ff23fSmrg		    index += 1;
1543209ff23fSmrg		    ErrorF("i2c write: 0x%x, 0x%x\n", (unsigned)reg,
1544209ff23fSmrg			   (unsigned)val);
1545b7e1c893Smrg		    RADEONDVOWriteByte(dvo->DVOChip, reg, val);
1546209ff23fSmrg		    break;
1547209ff23fSmrg		default:
1548209ff23fSmrg		    ErrorF("unknown id %d\n", id>>13);
1549209ff23fSmrg		    return FALSE;
1550209ff23fSmrg		};
1551209ff23fSmrg		id = RADEON_BIOS16(index);
1552209ff23fSmrg	    }
1553209ff23fSmrg	    return TRUE;
1554209ff23fSmrg	}
1555209ff23fSmrg    }
1556209ff23fSmrg
1557209ff23fSmrg    return FALSE;
1558209ff23fSmrg}
1559209ff23fSmrg
1560209ff23fSmrg/* support for init from bios tables
1561209ff23fSmrg *
1562209ff23fSmrg * Based heavily on the netbsd radeonfb driver
1563209ff23fSmrg * Written by Garrett D'Amore
1564209ff23fSmrg * Copyright (c) 2006 Itronix Inc.
1565209ff23fSmrg *
1566209ff23fSmrg */
1567209ff23fSmrg
1568209ff23fSmrg/* bios table defines */
1569209ff23fSmrg
1570209ff23fSmrg#define RADEON_TABLE_ENTRY_FLAG_MASK    0xe000
1571209ff23fSmrg#define RADEON_TABLE_ENTRY_INDEX_MASK   0x1fff
1572209ff23fSmrg#define RADEON_TABLE_ENTRY_COMMAND_MASK 0x00ff
1573209ff23fSmrg
1574209ff23fSmrg#define RADEON_TABLE_FLAG_WRITE_INDEXED 0x0000
1575209ff23fSmrg#define RADEON_TABLE_FLAG_WRITE_DIRECT  0x2000
1576209ff23fSmrg#define RADEON_TABLE_FLAG_MASK_INDEXED  0x4000
1577209ff23fSmrg#define RADEON_TABLE_FLAG_MASK_DIRECT   0x6000
1578209ff23fSmrg#define RADEON_TABLE_FLAG_DELAY         0x8000
1579209ff23fSmrg#define RADEON_TABLE_FLAG_SCOMMAND      0xa000
1580209ff23fSmrg
1581209ff23fSmrg#define RADEON_TABLE_SCOMMAND_WAIT_MC_BUSY_MASK       0x03
1582209ff23fSmrg#define RADEON_TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE 0x08
1583209ff23fSmrg
1584209ff23fSmrg#define RADEON_PLL_FLAG_MASK      0xc0
1585209ff23fSmrg#define RADEON_PLL_INDEX_MASK     0x3f
1586209ff23fSmrg
1587209ff23fSmrg#define RADEON_PLL_FLAG_WRITE     0x00
1588209ff23fSmrg#define RADEON_PLL_FLAG_MASK_BYTE 0x40
1589209ff23fSmrg#define RADEON_PLL_FLAG_WAIT      0x80
1590209ff23fSmrg
1591209ff23fSmrg#define RADEON_PLL_WAIT_150MKS                    1
1592209ff23fSmrg#define RADEON_PLL_WAIT_5MS                       2
1593209ff23fSmrg#define RADEON_PLL_WAIT_MC_BUSY_MASK              3
1594209ff23fSmrg#define RADEON_PLL_WAIT_DLL_READY_MASK            4
1595209ff23fSmrg#define RADEON_PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24 5
1596209ff23fSmrg
1597209ff23fSmrgstatic uint16_t
1598209ff23fSmrgRADEONValidateBIOSOffset(ScrnInfoPtr pScrn, uint16_t offset)
1599209ff23fSmrg{
1600209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1601209ff23fSmrg    uint8_t revision = RADEON_BIOS8(offset - 1);
1602209ff23fSmrg
1603209ff23fSmrg    if (revision > 0x10) {
1604209ff23fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1605209ff23fSmrg                   "Bad revision %d for BIOS table\n", revision);
1606209ff23fSmrg        return 0;
1607209ff23fSmrg    }
1608209ff23fSmrg
1609209ff23fSmrg    if (offset < 0x60) {
1610209ff23fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1611209ff23fSmrg                   "Bad offset 0x%x for BIOS Table\n", offset);
1612209ff23fSmrg        return 0;
1613209ff23fSmrg    }
1614209ff23fSmrg
1615209ff23fSmrg    return offset;
1616209ff23fSmrg}
1617209ff23fSmrg
1618209ff23fSmrgBool
1619209ff23fSmrgRADEONGetBIOSInitTableOffsets(ScrnInfoPtr pScrn)
1620209ff23fSmrg{
1621209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1622209ff23fSmrg    uint8_t val;
1623209ff23fSmrg
1624209ff23fSmrg    if (!info->VBIOS) {
1625209ff23fSmrg	return FALSE;
1626209ff23fSmrg    } else {
1627209ff23fSmrg	if (info->IsAtomBios) {
1628209ff23fSmrg	    return FALSE;
1629209ff23fSmrg	} else {
1630209ff23fSmrg	    info->BiosTable.revision = RADEON_BIOS8(info->ROMHeaderStart + 4);
1631209ff23fSmrg	    info->BiosTable.rr1_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x0c);
1632209ff23fSmrg	    if (info->BiosTable.rr1_offset) {
1633209ff23fSmrg		info->BiosTable.rr1_offset =
1634209ff23fSmrg		    RADEONValidateBIOSOffset(pScrn, info->BiosTable.rr1_offset);
1635209ff23fSmrg	    }
1636209ff23fSmrg	    if (info->BiosTable.revision > 0x09)
1637209ff23fSmrg		return TRUE;
1638209ff23fSmrg	    info->BiosTable.rr2_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x4e);
1639209ff23fSmrg	    if (info->BiosTable.rr2_offset) {
1640209ff23fSmrg		info->BiosTable.rr2_offset =
1641209ff23fSmrg		    RADEONValidateBIOSOffset(pScrn, info->BiosTable.rr2_offset);
1642209ff23fSmrg	    }
1643209ff23fSmrg	    info->BiosTable.dyn_clk_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x52);
1644209ff23fSmrg	    if (info->BiosTable.dyn_clk_offset) {
1645209ff23fSmrg		info->BiosTable.dyn_clk_offset =
1646209ff23fSmrg		    RADEONValidateBIOSOffset(pScrn, info->BiosTable.dyn_clk_offset);
1647209ff23fSmrg	    }
1648209ff23fSmrg	    info->BiosTable.pll_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x46);
1649209ff23fSmrg	    if (info->BiosTable.pll_offset) {
1650209ff23fSmrg		info->BiosTable.pll_offset =
1651209ff23fSmrg		    RADEONValidateBIOSOffset(pScrn, info->BiosTable.pll_offset);
1652209ff23fSmrg	    }
1653209ff23fSmrg	    info->BiosTable.mem_config_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x48);
1654209ff23fSmrg	    if (info->BiosTable.mem_config_offset) {
1655209ff23fSmrg		info->BiosTable.mem_config_offset =
1656209ff23fSmrg		    RADEONValidateBIOSOffset(pScrn, info->BiosTable.mem_config_offset);
1657209ff23fSmrg	    }
1658209ff23fSmrg	    if (info->BiosTable.mem_config_offset) {
1659209ff23fSmrg		info->BiosTable.mem_reset_offset = info->BiosTable.mem_config_offset;
1660209ff23fSmrg		if (info->BiosTable.mem_reset_offset) {
1661209ff23fSmrg		    while (RADEON_BIOS8(info->BiosTable.mem_reset_offset))
1662209ff23fSmrg			info->BiosTable.mem_reset_offset++;
1663209ff23fSmrg		    info->BiosTable.mem_reset_offset++;
1664209ff23fSmrg		    info->BiosTable.mem_reset_offset += 2;
1665209ff23fSmrg		}
1666209ff23fSmrg	    }
1667209ff23fSmrg	    if (info->BiosTable.mem_config_offset) {
1668209ff23fSmrg		info->BiosTable.short_mem_offset = info->BiosTable.mem_config_offset;
1669209ff23fSmrg		if ((info->BiosTable.short_mem_offset != 0) &&
1670209ff23fSmrg		    (RADEON_BIOS8(info->BiosTable.short_mem_offset - 2) <= 64))
1671209ff23fSmrg		    info->BiosTable.short_mem_offset +=
1672209ff23fSmrg			RADEON_BIOS8(info->BiosTable.short_mem_offset - 3);
1673209ff23fSmrg	    }
1674209ff23fSmrg	    if (info->BiosTable.rr2_offset) {
1675209ff23fSmrg		info->BiosTable.rr3_offset = info->BiosTable.rr2_offset;
1676209ff23fSmrg		if (info->BiosTable.rr3_offset) {
1677209ff23fSmrg		    while ((val = RADEON_BIOS8(info->BiosTable.rr3_offset + 1)) != 0) {
1678209ff23fSmrg			if (val & 0x40)
1679209ff23fSmrg			    info->BiosTable.rr3_offset += 10;
1680209ff23fSmrg			else if (val & 0x80)
1681209ff23fSmrg			    info->BiosTable.rr3_offset += 4;
1682209ff23fSmrg			else
1683209ff23fSmrg			    info->BiosTable.rr3_offset += 6;
1684209ff23fSmrg		    }
1685209ff23fSmrg		    info->BiosTable.rr3_offset += 2;
1686209ff23fSmrg		}
1687209ff23fSmrg	    }
1688209ff23fSmrg
1689209ff23fSmrg	    if (info->BiosTable.rr3_offset) {
1690209ff23fSmrg		info->BiosTable.rr4_offset = info->BiosTable.rr3_offset;
1691209ff23fSmrg		if (info->BiosTable.rr4_offset) {
1692209ff23fSmrg		    while ((val = RADEON_BIOS8(info->BiosTable.rr4_offset + 1)) != 0) {
1693209ff23fSmrg			if (val & 0x40)
1694209ff23fSmrg			    info->BiosTable.rr4_offset += 10;
1695209ff23fSmrg			else if (val & 0x80)
1696209ff23fSmrg			    info->BiosTable.rr4_offset += 4;
1697209ff23fSmrg			else
1698209ff23fSmrg			    info->BiosTable.rr4_offset += 6;
1699209ff23fSmrg		    }
1700209ff23fSmrg		    info->BiosTable.rr4_offset += 2;
1701209ff23fSmrg		}
1702209ff23fSmrg	    }
1703209ff23fSmrg
1704209ff23fSmrg	    if (info->BiosTable.rr3_offset + 1 == info->BiosTable.pll_offset) {
1705209ff23fSmrg		info->BiosTable.rr3_offset = 0;
1706209ff23fSmrg		info->BiosTable.rr4_offset = 0;
1707209ff23fSmrg	    }
1708209ff23fSmrg
1709209ff23fSmrg	    return TRUE;
1710209ff23fSmrg
1711209ff23fSmrg	}
1712209ff23fSmrg    }
1713209ff23fSmrg}
1714209ff23fSmrg
1715209ff23fSmrgstatic void
1716209ff23fSmrgRADEONRestoreBIOSRegBlock(ScrnInfoPtr pScrn, uint16_t table_offset)
1717209ff23fSmrg{
1718209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1719209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1720209ff23fSmrg    uint16_t offset = table_offset;
1721209ff23fSmrg    uint16_t value, flag, index, count;
1722209ff23fSmrg    uint32_t andmask, ormask, val, channel_complete_mask;
1723209ff23fSmrg    uint8_t  command;
1724209ff23fSmrg
1725209ff23fSmrg    if (offset == 0)
1726209ff23fSmrg	return;
1727209ff23fSmrg
1728209ff23fSmrg    while ((value = RADEON_BIOS16(offset)) != 0) {
1729209ff23fSmrg	flag = value & RADEON_TABLE_ENTRY_FLAG_MASK;
1730209ff23fSmrg	index = value & RADEON_TABLE_ENTRY_INDEX_MASK;
1731209ff23fSmrg	command = value & RADEON_TABLE_ENTRY_COMMAND_MASK;
1732209ff23fSmrg
1733209ff23fSmrg	offset += 2;
1734209ff23fSmrg
1735209ff23fSmrg	switch (flag) {
1736209ff23fSmrg	case RADEON_TABLE_FLAG_WRITE_INDEXED:
1737209ff23fSmrg	    val = RADEON_BIOS32(offset);
1738209ff23fSmrg	    ErrorF("WRITE INDEXED: 0x%x 0x%x\n",
1739209ff23fSmrg		   index, (unsigned)val);
1740209ff23fSmrg	    OUTREG(RADEON_MM_INDEX, index);
1741209ff23fSmrg	    OUTREG(RADEON_MM_DATA, val);
1742209ff23fSmrg	    offset += 4;
1743209ff23fSmrg	    break;
1744209ff23fSmrg
1745209ff23fSmrg	case RADEON_TABLE_FLAG_WRITE_DIRECT:
1746209ff23fSmrg	    val = RADEON_BIOS32(offset);
1747209ff23fSmrg	    ErrorF("WRITE DIRECT: 0x%x 0x%x\n", index, (unsigned)val);
1748209ff23fSmrg	    OUTREG(index, val);
1749209ff23fSmrg	    offset += 4;
1750209ff23fSmrg	    break;
1751209ff23fSmrg
1752209ff23fSmrg	case RADEON_TABLE_FLAG_MASK_INDEXED:
1753209ff23fSmrg	    andmask = RADEON_BIOS32(offset);
1754209ff23fSmrg	    offset += 4;
1755209ff23fSmrg	    ormask = RADEON_BIOS32(offset);
1756209ff23fSmrg	    offset += 4;
1757209ff23fSmrg	    ErrorF("MASK INDEXED: 0x%x 0x%x 0x%x\n",
1758209ff23fSmrg		   index, (unsigned)andmask, (unsigned)ormask);
1759209ff23fSmrg	    OUTREG(RADEON_MM_INDEX, index);
1760209ff23fSmrg	    val = INREG(RADEON_MM_DATA);
1761209ff23fSmrg	    val = (val & andmask) | ormask;
1762209ff23fSmrg	    OUTREG(RADEON_MM_DATA, val);
1763209ff23fSmrg	    break;
1764209ff23fSmrg
1765209ff23fSmrg	case RADEON_TABLE_FLAG_MASK_DIRECT:
1766209ff23fSmrg	    andmask = RADEON_BIOS32(offset);
1767209ff23fSmrg	    offset += 4;
1768209ff23fSmrg	    ormask = RADEON_BIOS32(offset);
1769209ff23fSmrg	    offset += 4;
1770209ff23fSmrg	    ErrorF("MASK DIRECT: 0x%x 0x%x 0x%x\n",
1771209ff23fSmrg		   index, (unsigned)andmask, (unsigned)ormask);
1772209ff23fSmrg	    val = INREG(index);
1773209ff23fSmrg	    val = (val & andmask) | ormask;
1774209ff23fSmrg	    OUTREG(index, val);
1775209ff23fSmrg	    break;
1776209ff23fSmrg
1777209ff23fSmrg	case RADEON_TABLE_FLAG_DELAY:
1778209ff23fSmrg	    count = RADEON_BIOS16(offset);
1779209ff23fSmrg	    ErrorF("delay: %d\n", count);
1780209ff23fSmrg	    usleep(count);
1781209ff23fSmrg	    offset += 2;
1782209ff23fSmrg	    break;
1783209ff23fSmrg
1784209ff23fSmrg	case RADEON_TABLE_FLAG_SCOMMAND:
1785209ff23fSmrg	    ErrorF("SCOMMAND 0x%x\n", command);
1786209ff23fSmrg	    switch (command) {
1787209ff23fSmrg	    case RADEON_TABLE_SCOMMAND_WAIT_MC_BUSY_MASK:
1788209ff23fSmrg		count = RADEON_BIOS16(offset);
1789209ff23fSmrg		ErrorF("SCOMMAND_WAIT_MC_BUSY_MASK %d\n", count);
1790209ff23fSmrg		while (count--) {
1791209ff23fSmrg		    if (!(INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) &
1792209ff23fSmrg			  RADEON_MC_BUSY))
1793209ff23fSmrg			break;
1794209ff23fSmrg		}
1795209ff23fSmrg		break;
1796209ff23fSmrg
1797209ff23fSmrg	    case RADEON_TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE:
1798209ff23fSmrg		count = RADEON_BIOS16(offset);
1799209ff23fSmrg		ErrorF("SCOMMAND_WAIT_MEM_PWRUP_COMPLETE %d\n", count);
1800209ff23fSmrg		/* may need to take into account how many memory channels
1801209ff23fSmrg		 * each card has
1802209ff23fSmrg		 */
1803209ff23fSmrg		if (IS_R300_VARIANT)
1804209ff23fSmrg		    channel_complete_mask = R300_MEM_PWRUP_COMPLETE;
1805209ff23fSmrg		else
1806209ff23fSmrg		    channel_complete_mask = RADEON_MEM_PWRUP_COMPLETE;
1807209ff23fSmrg		while (count--) {
1808209ff23fSmrg		    /* XXX: may need indexed access */
1809209ff23fSmrg		    if ((INREG(RADEON_MEM_STR_CNTL) &
1810209ff23fSmrg			 channel_complete_mask) ==
1811209ff23fSmrg		        channel_complete_mask)
1812209ff23fSmrg			break;
1813209ff23fSmrg		}
1814209ff23fSmrg		break;
1815209ff23fSmrg
1816209ff23fSmrg	    }
1817209ff23fSmrg	    offset += 2;
1818209ff23fSmrg	    break;
1819209ff23fSmrg	}
1820209ff23fSmrg    }
1821209ff23fSmrg}
1822209ff23fSmrg
1823209ff23fSmrgstatic void
1824209ff23fSmrgRADEONRestoreBIOSMemBlock(ScrnInfoPtr pScrn, uint16_t table_offset)
1825209ff23fSmrg{
1826209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1827209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1828209ff23fSmrg    uint16_t offset = table_offset;
1829209ff23fSmrg    uint16_t count;
1830209ff23fSmrg    uint32_t ormask, val, channel_complete_mask;
1831209ff23fSmrg    uint8_t  index;
1832209ff23fSmrg
1833209ff23fSmrg    if (offset == 0)
1834209ff23fSmrg	return;
1835209ff23fSmrg
1836209ff23fSmrg    while ((index = RADEON_BIOS8(offset)) != 0xff) {
1837209ff23fSmrg	offset++;
1838209ff23fSmrg	if (index == 0x0f) {
1839209ff23fSmrg	    count = 20000;
1840209ff23fSmrg	    ErrorF("MEM_WAIT_MEM_PWRUP_COMPLETE %d\n", count);
1841209ff23fSmrg	    /* may need to take into account how many memory channels
1842209ff23fSmrg	     * each card has
1843209ff23fSmrg	     */
1844209ff23fSmrg	    if (IS_R300_VARIANT)
1845209ff23fSmrg		channel_complete_mask = R300_MEM_PWRUP_COMPLETE;
1846209ff23fSmrg	    else
1847209ff23fSmrg		channel_complete_mask = RADEON_MEM_PWRUP_COMPLETE;
1848209ff23fSmrg	    while (count--) {
1849209ff23fSmrg		/* XXX: may need indexed access */
1850209ff23fSmrg		if ((INREG(RADEON_MEM_STR_CNTL) &
1851209ff23fSmrg		     channel_complete_mask) ==
1852209ff23fSmrg		    channel_complete_mask)
1853209ff23fSmrg		    break;
1854209ff23fSmrg	    }
1855209ff23fSmrg	} else {
1856209ff23fSmrg	    ormask = RADEON_BIOS16(offset);
1857209ff23fSmrg	    offset += 2;
1858209ff23fSmrg
1859209ff23fSmrg	    ErrorF("INDEX RADEON_MEM_SDRAM_MODE_REG %x %x\n",
1860209ff23fSmrg		   RADEON_SDRAM_MODE_MASK, (unsigned)ormask);
1861209ff23fSmrg
1862209ff23fSmrg	    /* can this use direct access? */
1863209ff23fSmrg	    OUTREG(RADEON_MM_INDEX, RADEON_MEM_SDRAM_MODE_REG);
1864209ff23fSmrg	    val = INREG(RADEON_MM_DATA);
1865209ff23fSmrg	    val = (val & RADEON_SDRAM_MODE_MASK) | ormask;
1866209ff23fSmrg	    OUTREG(RADEON_MM_DATA, val);
1867209ff23fSmrg
1868209ff23fSmrg	    ormask = (uint32_t)index << 24;
1869209ff23fSmrg
1870209ff23fSmrg	    ErrorF("INDEX RADEON_MEM_SDRAM_MODE_REG %x %x\n",
1871209ff23fSmrg		   RADEON_B3MEM_RESET_MASK, (unsigned)ormask);
1872209ff23fSmrg
1873209ff23fSmrg            /* can this use direct access? */
1874209ff23fSmrg            OUTREG(RADEON_MM_INDEX, RADEON_MEM_SDRAM_MODE_REG);
1875209ff23fSmrg            val = INREG(RADEON_MM_DATA);
1876209ff23fSmrg            val = (val & RADEON_B3MEM_RESET_MASK) | ormask;
1877209ff23fSmrg            OUTREG(RADEON_MM_DATA, val);
1878209ff23fSmrg	}
1879209ff23fSmrg    }
1880209ff23fSmrg}
1881209ff23fSmrg
1882209ff23fSmrgstatic void
1883209ff23fSmrgRADEONRestoreBIOSPllBlock(ScrnInfoPtr pScrn, uint16_t table_offset)
1884209ff23fSmrg{
1885209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1886209ff23fSmrg    uint16_t offset = table_offset;
1887209ff23fSmrg    uint8_t  index, shift;
1888209ff23fSmrg    uint32_t andmask, ormask, val, clk_pwrmgt_cntl;
1889209ff23fSmrg    uint16_t count;
1890209ff23fSmrg
1891209ff23fSmrg    if (offset == 0)
1892209ff23fSmrg	return;
1893209ff23fSmrg
1894209ff23fSmrg    while ((index = RADEON_BIOS8(offset)) != 0) {
1895209ff23fSmrg	offset++;
1896209ff23fSmrg
1897209ff23fSmrg	switch (index & RADEON_PLL_FLAG_MASK) {
1898209ff23fSmrg	case RADEON_PLL_FLAG_WAIT:
1899209ff23fSmrg	    switch (index & RADEON_PLL_INDEX_MASK) {
1900209ff23fSmrg	    case RADEON_PLL_WAIT_150MKS:
1901209ff23fSmrg		ErrorF("delay: 150 us\n");
1902209ff23fSmrg		usleep(150);
1903209ff23fSmrg		break;
1904209ff23fSmrg	    case RADEON_PLL_WAIT_5MS:
1905209ff23fSmrg		ErrorF("delay: 5 ms\n");
1906209ff23fSmrg		usleep(5000);
1907209ff23fSmrg		break;
1908209ff23fSmrg
1909209ff23fSmrg	    case RADEON_PLL_WAIT_MC_BUSY_MASK:
1910209ff23fSmrg		count = 1000;
1911209ff23fSmrg		ErrorF("PLL_WAIT_MC_BUSY_MASK %d\n", count);
1912209ff23fSmrg		while (count--) {
1913209ff23fSmrg		    if (!(INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) &
1914209ff23fSmrg			  RADEON_MC_BUSY))
1915209ff23fSmrg			break;
1916209ff23fSmrg		}
1917209ff23fSmrg		break;
1918209ff23fSmrg
1919209ff23fSmrg	    case RADEON_PLL_WAIT_DLL_READY_MASK:
1920209ff23fSmrg		count = 1000;
1921209ff23fSmrg		ErrorF("PLL_WAIT_DLL_READY_MASK %d\n", count);
1922209ff23fSmrg		while (count--) {
1923209ff23fSmrg		    if (INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) &
1924209ff23fSmrg			RADEON_DLL_READY)
1925209ff23fSmrg			break;
1926209ff23fSmrg		}
1927209ff23fSmrg		break;
1928209ff23fSmrg
1929209ff23fSmrg	    case RADEON_PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24:
1930209ff23fSmrg		ErrorF("PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24\n");
1931209ff23fSmrg		clk_pwrmgt_cntl = INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL);
1932209ff23fSmrg		if (clk_pwrmgt_cntl & RADEON_CG_NO1_DEBUG_0) {
1933209ff23fSmrg		    val = INPLL(pScrn, RADEON_MCLK_CNTL);
1934209ff23fSmrg		    /* is this right? */
1935209ff23fSmrg		    val = (val & 0xFFFF0000) | 0x1111; /* seems like we should clear these... */
1936209ff23fSmrg		    OUTPLL(pScrn, RADEON_MCLK_CNTL, val);
1937209ff23fSmrg		    usleep(10000);
1938209ff23fSmrg		    OUTPLL(pScrn, RADEON_CLK_PWRMGT_CNTL,
1939209ff23fSmrg			   clk_pwrmgt_cntl & ~RADEON_CG_NO1_DEBUG_0);
1940209ff23fSmrg		    usleep(10000);
1941209ff23fSmrg		}
1942209ff23fSmrg		break;
1943209ff23fSmrg	    }
1944209ff23fSmrg	    break;
1945209ff23fSmrg
1946209ff23fSmrg	case RADEON_PLL_FLAG_MASK_BYTE:
1947209ff23fSmrg	    shift = RADEON_BIOS8(offset) * 8;
1948209ff23fSmrg	    offset++;
1949209ff23fSmrg
1950209ff23fSmrg	    andmask =
1951209ff23fSmrg		(((uint32_t)RADEON_BIOS8(offset)) << shift) |
1952209ff23fSmrg		~((uint32_t)0xff << shift);
1953209ff23fSmrg	    offset++;
1954209ff23fSmrg
1955209ff23fSmrg	    ormask = ((uint32_t)RADEON_BIOS8(offset)) << shift;
1956209ff23fSmrg	    offset++;
1957209ff23fSmrg
1958209ff23fSmrg	    ErrorF("PLL_MASK_BYTE 0x%x 0x%x 0x%x 0x%x\n",
1959209ff23fSmrg		   index, shift, (unsigned)andmask, (unsigned)ormask);
1960209ff23fSmrg	    val = INPLL(pScrn, index);
1961209ff23fSmrg	    val = (val & andmask) | ormask;
1962209ff23fSmrg	    OUTPLL(pScrn, index, val);
1963209ff23fSmrg	    break;
1964209ff23fSmrg
1965209ff23fSmrg	case RADEON_PLL_FLAG_WRITE:
1966209ff23fSmrg	    val = RADEON_BIOS32(offset);
1967209ff23fSmrg	    ErrorF("PLL_WRITE 0x%x 0x%x\n", index, (unsigned)val);
1968209ff23fSmrg	    OUTPLL(pScrn, index, val);
1969209ff23fSmrg	    offset += 4;
1970209ff23fSmrg	    break;
1971209ff23fSmrg	}
1972209ff23fSmrg    }
1973209ff23fSmrg}
1974209ff23fSmrg
1975209ff23fSmrgBool
1976209ff23fSmrgRADEONPostCardFromBIOSTables(ScrnInfoPtr pScrn)
1977209ff23fSmrg{
1978209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1979209ff23fSmrg
1980209ff23fSmrg    if (!info->VBIOS) {
1981209ff23fSmrg	return FALSE;
1982209ff23fSmrg    } else {
1983209ff23fSmrg	if (info->IsAtomBios) {
1984209ff23fSmrg	    return FALSE;
1985209ff23fSmrg	} else {
1986209ff23fSmrg	    if (info->BiosTable.rr1_offset) {
1987209ff23fSmrg		ErrorF("rr1 restore, 0x%x\n", info->BiosTable.rr1_offset);
1988209ff23fSmrg		RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr1_offset);
1989209ff23fSmrg	    }
1990209ff23fSmrg	    if (info->BiosTable.revision < 0x09) {
1991209ff23fSmrg		if (info->BiosTable.pll_offset) {
1992209ff23fSmrg		    ErrorF("pll restore, 0x%x\n", info->BiosTable.pll_offset);
1993209ff23fSmrg		    RADEONRestoreBIOSPllBlock(pScrn, info->BiosTable.pll_offset);
1994209ff23fSmrg		}
1995209ff23fSmrg		if (info->BiosTable.rr2_offset) {
1996209ff23fSmrg		    ErrorF("rr2 restore, 0x%x\n", info->BiosTable.rr2_offset);
1997209ff23fSmrg		    RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr2_offset);
1998209ff23fSmrg		}
1999209ff23fSmrg		if (info->BiosTable.rr4_offset) {
2000209ff23fSmrg		    ErrorF("rr4 restore, 0x%x\n", info->BiosTable.rr4_offset);
2001209ff23fSmrg		    RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr4_offset);
2002209ff23fSmrg		}
2003209ff23fSmrg		if (info->BiosTable.mem_reset_offset) {
2004209ff23fSmrg		    ErrorF("mem reset restore, 0x%x\n", info->BiosTable.mem_reset_offset);
2005209ff23fSmrg		    RADEONRestoreBIOSMemBlock(pScrn, info->BiosTable.mem_reset_offset);
2006209ff23fSmrg		}
2007209ff23fSmrg		if (info->BiosTable.rr3_offset) {
2008209ff23fSmrg		    ErrorF("rr3 restore, 0x%x\n", info->BiosTable.rr3_offset);
2009209ff23fSmrg		    RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr3_offset);
2010209ff23fSmrg		}
2011209ff23fSmrg		if (info->BiosTable.dyn_clk_offset) {
2012209ff23fSmrg		    ErrorF("dyn_clk restore, 0x%x\n", info->BiosTable.dyn_clk_offset);
2013209ff23fSmrg		    RADEONRestoreBIOSPllBlock(pScrn, info->BiosTable.dyn_clk_offset);
2014209ff23fSmrg		}
2015209ff23fSmrg	    }
2016209ff23fSmrg	}
2017209ff23fSmrg    }
2018209ff23fSmrg    return TRUE;
2019209ff23fSmrg}
2020