radeon_bios.c revision 2f39173d
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
110ad43ddacSmrg    if (info->ChipFamily >= CHIP_FAMILY_RV770) {
111ad43ddacSmrg	uint32_t viph_control   = INREG(RADEON_VIPH_CONTROL);
112ad43ddacSmrg	uint32_t bus_cntl       = INREG(RADEON_BUS_CNTL);
113ad43ddacSmrg	uint32_t d1vga_control  = INREG(AVIVO_D1VGA_CONTROL);
114ad43ddacSmrg	uint32_t d2vga_control  = INREG(AVIVO_D2VGA_CONTROL);
115ad43ddacSmrg	uint32_t vga_render_control  = INREG(AVIVO_VGA_RENDER_CONTROL);
116ad43ddacSmrg	uint32_t rom_cntl       = INREG(R600_ROM_CNTL);
117ad43ddacSmrg	uint32_t cg_spll_func_cntl = 0;
118ad43ddacSmrg	uint32_t cg_spll_status;
119ad43ddacSmrg
120ad43ddacSmrg	/* disable VIP */
121ad43ddacSmrg	OUTREG(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
122ad43ddacSmrg
123ad43ddacSmrg	/* enable the rom */
124ad43ddacSmrg	OUTREG(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
125ad43ddacSmrg
126ad43ddacSmrg	/* Disable VGA mode */
127ad43ddacSmrg	OUTREG(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
128ad43ddacSmrg						       AVIVO_DVGA_CONTROL_TIMING_SELECT)));
129ad43ddacSmrg	OUTREG(AVIVO_D2VGA_CONTROL, (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
130ad43ddacSmrg						       AVIVO_DVGA_CONTROL_TIMING_SELECT)));
131ad43ddacSmrg	OUTREG(AVIVO_VGA_RENDER_CONTROL, (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
132ad43ddacSmrg
133ad43ddacSmrg	if (info->ChipFamily == CHIP_FAMILY_RV730) {
134ad43ddacSmrg	    cg_spll_func_cntl = INREG(R600_CG_SPLL_FUNC_CNTL);
135ad43ddacSmrg
136ad43ddacSmrg	    /* enable bypass mode */
137ad43ddacSmrg	    OUTREG(R600_CG_SPLL_FUNC_CNTL, (cg_spll_func_cntl | R600_SPLL_BYPASS_EN));
138ad43ddacSmrg
139ad43ddacSmrg	    /* wait for SPLL_CHG_STATUS to change to 1 */
140ad43ddacSmrg	    cg_spll_status = 0;
141ad43ddacSmrg	    while (!(cg_spll_status & R600_SPLL_CHG_STATUS))
142ad43ddacSmrg		cg_spll_status = INREG(R600_CG_SPLL_STATUS);
143ad43ddacSmrg
144ad43ddacSmrg	    OUTREG(R600_ROM_CNTL, (rom_cntl & ~R600_SCK_OVERWRITE));
145ad43ddacSmrg	} else
146ad43ddacSmrg	    OUTREG(R600_ROM_CNTL, (rom_cntl | R600_SCK_OVERWRITE));
147ad43ddacSmrg
148ad43ddacSmrg	ret = radeon_read_bios(pScrn);
149ad43ddacSmrg
150ad43ddacSmrg	/* restore regs */
151ad43ddacSmrg	if (info->ChipFamily == CHIP_FAMILY_RV730) {
152ad43ddacSmrg	    OUTREG(R600_CG_SPLL_FUNC_CNTL, cg_spll_func_cntl);
153ad43ddacSmrg
154ad43ddacSmrg	    /* wait for SPLL_CHG_STATUS to change to 1 */
155ad43ddacSmrg	    cg_spll_status = 0;
156ad43ddacSmrg	    while (!(cg_spll_status & R600_SPLL_CHG_STATUS))
157ad43ddacSmrg		cg_spll_status = INREG(R600_CG_SPLL_STATUS);
158ad43ddacSmrg	}
159ad43ddacSmrg	OUTREG(RADEON_VIPH_CONTROL, viph_control);
160ad43ddacSmrg	OUTREG(RADEON_BUS_CNTL, bus_cntl);
161ad43ddacSmrg	OUTREG(AVIVO_D1VGA_CONTROL, d1vga_control);
162ad43ddacSmrg	OUTREG(AVIVO_D2VGA_CONTROL, d2vga_control);
163ad43ddacSmrg	OUTREG(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
164ad43ddacSmrg	OUTREG(R600_ROM_CNTL, rom_cntl);
165ad43ddacSmrg    } else if (info->ChipFamily >= CHIP_FAMILY_R600) {
166209ff23fSmrg	uint32_t viph_control   = INREG(RADEON_VIPH_CONTROL);
167209ff23fSmrg	uint32_t bus_cntl       = INREG(RADEON_BUS_CNTL);
168209ff23fSmrg	uint32_t d1vga_control  = INREG(AVIVO_D1VGA_CONTROL);
169209ff23fSmrg	uint32_t d2vga_control  = INREG(AVIVO_D2VGA_CONTROL);
170209ff23fSmrg	uint32_t vga_render_control  = INREG(AVIVO_VGA_RENDER_CONTROL);
171209ff23fSmrg	uint32_t rom_cntl       = INREG(R600_ROM_CNTL);
172209ff23fSmrg	uint32_t general_pwrmgt = INREG(R600_GENERAL_PWRMGT);
173209ff23fSmrg	uint32_t low_vid_lower_gpio_cntl    = INREG(R600_LOW_VID_LOWER_GPIO_CNTL);
174209ff23fSmrg	uint32_t medium_vid_lower_gpio_cntl = INREG(R600_MEDIUM_VID_LOWER_GPIO_CNTL);
175209ff23fSmrg	uint32_t high_vid_lower_gpio_cntl   = INREG(R600_HIGH_VID_LOWER_GPIO_CNTL);
176209ff23fSmrg	uint32_t ctxsw_vid_lower_gpio_cntl  = INREG(R600_CTXSW_VID_LOWER_GPIO_CNTL);
177209ff23fSmrg	uint32_t lower_gpio_enable          = INREG(R600_LOWER_GPIO_ENABLE);
178209ff23fSmrg
179209ff23fSmrg	/* disable VIP */
180209ff23fSmrg	OUTREG(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
181209ff23fSmrg
182209ff23fSmrg	/* enable the rom */
183209ff23fSmrg	OUTREG(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
184209ff23fSmrg
185ad43ddacSmrg	/* Disable VGA mode */
186209ff23fSmrg	OUTREG(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
187209ff23fSmrg						       AVIVO_DVGA_CONTROL_TIMING_SELECT)));
188209ff23fSmrg	OUTREG(AVIVO_D2VGA_CONTROL, (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
189209ff23fSmrg						       AVIVO_DVGA_CONTROL_TIMING_SELECT)));
190209ff23fSmrg	OUTREG(AVIVO_VGA_RENDER_CONTROL, (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
191209ff23fSmrg
192209ff23fSmrg	OUTREG(R600_ROM_CNTL, ((rom_cntl & ~R600_SCK_PRESCALE_CRYSTAL_CLK_MASK) |
193209ff23fSmrg			       (1 << R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT) |
194209ff23fSmrg			       R600_SCK_OVERWRITE));
195209ff23fSmrg
196209ff23fSmrg	OUTREG(R600_GENERAL_PWRMGT, (general_pwrmgt & ~R600_OPEN_DRAIN_PADS));
197209ff23fSmrg
198209ff23fSmrg	OUTREG(R600_LOW_VID_LOWER_GPIO_CNTL, (low_vid_lower_gpio_cntl & ~0x400));
199209ff23fSmrg
200209ff23fSmrg	OUTREG(R600_MEDIUM_VID_LOWER_GPIO_CNTL, (medium_vid_lower_gpio_cntl & ~0x400));
201209ff23fSmrg
202209ff23fSmrg	OUTREG(R600_HIGH_VID_LOWER_GPIO_CNTL, (high_vid_lower_gpio_cntl & ~0x400));
203209ff23fSmrg
204209ff23fSmrg	OUTREG(R600_CTXSW_VID_LOWER_GPIO_CNTL, (ctxsw_vid_lower_gpio_cntl & ~0x400));
205209ff23fSmrg
206209ff23fSmrg	OUTREG(R600_LOWER_GPIO_ENABLE, (lower_gpio_enable | 0x400));
207209ff23fSmrg
208209ff23fSmrg	ret = radeon_read_bios(pScrn);
209209ff23fSmrg
210209ff23fSmrg	/* restore regs */
211209ff23fSmrg	OUTREG(RADEON_VIPH_CONTROL, viph_control);
212209ff23fSmrg	OUTREG(RADEON_BUS_CNTL, bus_cntl);
213209ff23fSmrg	OUTREG(AVIVO_D1VGA_CONTROL, d1vga_control);
214209ff23fSmrg	OUTREG(AVIVO_D2VGA_CONTROL, d2vga_control);
215209ff23fSmrg	OUTREG(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
216209ff23fSmrg	OUTREG(R600_ROM_CNTL, rom_cntl);
217209ff23fSmrg	OUTREG(R600_GENERAL_PWRMGT, general_pwrmgt);
218209ff23fSmrg	OUTREG(R600_LOW_VID_LOWER_GPIO_CNTL, low_vid_lower_gpio_cntl);
219209ff23fSmrg	OUTREG(R600_MEDIUM_VID_LOWER_GPIO_CNTL, medium_vid_lower_gpio_cntl);
220209ff23fSmrg	OUTREG(R600_HIGH_VID_LOWER_GPIO_CNTL, high_vid_lower_gpio_cntl);
221209ff23fSmrg	OUTREG(R600_CTXSW_VID_LOWER_GPIO_CNTL, ctxsw_vid_lower_gpio_cntl);
222209ff23fSmrg	OUTREG(R600_LOWER_GPIO_ENABLE, lower_gpio_enable);
223209ff23fSmrg
224209ff23fSmrg    } else if (info->ChipFamily >= CHIP_FAMILY_RV515) {
225209ff23fSmrg	uint32_t seprom_cntl1   = INREG(RADEON_SEPROM_CNTL1);
226209ff23fSmrg	uint32_t viph_control   = INREG(RADEON_VIPH_CONTROL);
227209ff23fSmrg	uint32_t bus_cntl       = INREG(RADEON_BUS_CNTL);
228209ff23fSmrg	uint32_t d1vga_control  = INREG(AVIVO_D1VGA_CONTROL);
229209ff23fSmrg	uint32_t d2vga_control  = INREG(AVIVO_D2VGA_CONTROL);
230209ff23fSmrg	uint32_t vga_render_control  = INREG(AVIVO_VGA_RENDER_CONTROL);
231209ff23fSmrg	uint32_t gpiopad_a      = INREG(RADEON_GPIOPAD_A);
232209ff23fSmrg	uint32_t gpiopad_en     = INREG(RADEON_GPIOPAD_EN);
233209ff23fSmrg	uint32_t gpiopad_mask   = INREG(RADEON_GPIOPAD_MASK);
234209ff23fSmrg
235209ff23fSmrg	OUTREG(RADEON_SEPROM_CNTL1, ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) |
236209ff23fSmrg				     (0xc << RADEON_SCK_PRESCALE_SHIFT)));
237209ff23fSmrg
238209ff23fSmrg	OUTREG(RADEON_GPIOPAD_A, 0);
239209ff23fSmrg	OUTREG(RADEON_GPIOPAD_EN, 0);
240209ff23fSmrg	OUTREG(RADEON_GPIOPAD_MASK, 0);
241209ff23fSmrg
242209ff23fSmrg	/* disable VIP */
243209ff23fSmrg	OUTREG(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
244209ff23fSmrg
245209ff23fSmrg	/* enable the rom */
246209ff23fSmrg	OUTREG(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
247209ff23fSmrg
248209ff23fSmrg        /* Disable VGA mode */
249209ff23fSmrg	OUTREG(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
250209ff23fSmrg						       AVIVO_DVGA_CONTROL_TIMING_SELECT)));
251209ff23fSmrg	OUTREG(AVIVO_D2VGA_CONTROL, (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
252209ff23fSmrg						       AVIVO_DVGA_CONTROL_TIMING_SELECT)));
253209ff23fSmrg	OUTREG(AVIVO_VGA_RENDER_CONTROL, (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
254209ff23fSmrg
255209ff23fSmrg	ret = radeon_read_bios(pScrn);
256209ff23fSmrg
257209ff23fSmrg	/* restore regs */
258209ff23fSmrg	OUTREG(RADEON_SEPROM_CNTL1, seprom_cntl1);
259209ff23fSmrg	OUTREG(RADEON_VIPH_CONTROL, viph_control);
260209ff23fSmrg	OUTREG(RADEON_BUS_CNTL, bus_cntl);
261209ff23fSmrg	OUTREG(AVIVO_D1VGA_CONTROL, d1vga_control);
262209ff23fSmrg	OUTREG(AVIVO_D2VGA_CONTROL, d2vga_control);
263209ff23fSmrg	OUTREG(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
264209ff23fSmrg	OUTREG(RADEON_GPIOPAD_A, gpiopad_a);
265209ff23fSmrg	OUTREG(RADEON_GPIOPAD_EN, gpiopad_en);
266209ff23fSmrg	OUTREG(RADEON_GPIOPAD_MASK, gpiopad_mask);
267209ff23fSmrg
268209ff23fSmrg    } else {
269209ff23fSmrg	uint32_t seprom_cntl1   = INREG(RADEON_SEPROM_CNTL1);
270209ff23fSmrg	uint32_t viph_control   = INREG(RADEON_VIPH_CONTROL);
271209ff23fSmrg	uint32_t bus_cntl       = INREG(RADEON_BUS_CNTL);
272209ff23fSmrg	uint32_t crtc_gen_cntl  = INREG(RADEON_CRTC_GEN_CNTL);
273209ff23fSmrg	uint32_t crtc2_gen_cntl = 0;
274209ff23fSmrg	uint32_t crtc_ext_cntl  = INREG(RADEON_CRTC_EXT_CNTL);
275209ff23fSmrg	uint32_t fp2_gen_cntl   = 0;
276209ff23fSmrg
277209ff23fSmrg	if (PCI_DEV_DEVICE_ID(info->PciInfo) == PCI_CHIP_RV100_QY)
278209ff23fSmrg	    fp2_gen_cntl   = INREG(RADEON_FP2_GEN_CNTL);
279209ff23fSmrg
280209ff23fSmrg	if (pRADEONEnt->HasCRTC2)
281209ff23fSmrg	    crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL);
282209ff23fSmrg
283209ff23fSmrg	OUTREG(RADEON_SEPROM_CNTL1, ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) |
284209ff23fSmrg				     (0xc << RADEON_SCK_PRESCALE_SHIFT)));
285209ff23fSmrg
286209ff23fSmrg	/* disable VIP */
287209ff23fSmrg	OUTREG(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
288209ff23fSmrg
289209ff23fSmrg	/* enable the rom */
290209ff23fSmrg	OUTREG(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
291209ff23fSmrg
292209ff23fSmrg        /* Turn off mem requests and CRTC for both controllers */
293209ff23fSmrg	OUTREG(RADEON_CRTC_GEN_CNTL, ((crtc_gen_cntl & ~RADEON_CRTC_EN) |
294209ff23fSmrg				      (RADEON_CRTC_DISP_REQ_EN_B |
295209ff23fSmrg				       RADEON_CRTC_EXT_DISP_EN)));
296209ff23fSmrg	if (pRADEONEnt->HasCRTC2)
297209ff23fSmrg	    OUTREG(RADEON_CRTC2_GEN_CNTL, ((crtc2_gen_cntl & ~RADEON_CRTC2_EN) |
298209ff23fSmrg					   RADEON_CRTC2_DISP_REQ_EN_B));
299209ff23fSmrg
300209ff23fSmrg        /* Turn off CRTC */
301209ff23fSmrg	OUTREG(RADEON_CRTC_EXT_CNTL, ((crtc_ext_cntl & ~RADEON_CRTC_CRT_ON) |
302209ff23fSmrg				      (RADEON_CRTC_SYNC_TRISTAT |
303209ff23fSmrg				       RADEON_CRTC_DISPLAY_DIS)));
304209ff23fSmrg
305209ff23fSmrg	if (PCI_DEV_DEVICE_ID(info->PciInfo) == PCI_CHIP_RV100_QY)
306209ff23fSmrg	    OUTREG(RADEON_FP2_GEN_CNTL, (fp2_gen_cntl & ~RADEON_FP2_ON));
307209ff23fSmrg
308209ff23fSmrg	ret = radeon_read_bios(pScrn);
309209ff23fSmrg
310209ff23fSmrg	/* restore regs */
311209ff23fSmrg	OUTREG(RADEON_SEPROM_CNTL1, seprom_cntl1);
312209ff23fSmrg	OUTREG(RADEON_VIPH_CONTROL, viph_control);
313209ff23fSmrg	OUTREG(RADEON_BUS_CNTL, bus_cntl);
314209ff23fSmrg	OUTREG(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
315209ff23fSmrg	if (pRADEONEnt->HasCRTC2)
316209ff23fSmrg	    OUTREG(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
317209ff23fSmrg	OUTREG(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
318209ff23fSmrg	if (PCI_DEV_DEVICE_ID(info->PciInfo) == PCI_CHIP_RV100_QY)
319209ff23fSmrg	    OUTREG(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
320209ff23fSmrg    }
321209ff23fSmrg    return ret;
322209ff23fSmrg}
323209ff23fSmrg
324b7e1c893SmrgBool
325b7e1c893Smrgradeon_card_posted(ScrnInfoPtr pScrn)
326b7e1c893Smrg{
327b7e1c893Smrg    RADEONInfoPtr info     = RADEONPTR(pScrn);
328b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
329b7e1c893Smrg    uint32_t reg;
330b7e1c893Smrg
331c503f109Smrg    /* first check CRTCs */
332b7e1c893Smrg    if (IS_AVIVO_VARIANT) {
333b7e1c893Smrg	reg = INREG(AVIVO_D1CRTC_CONTROL) | INREG(AVIVO_D2CRTC_CONTROL);
334b7e1c893Smrg	if (reg & AVIVO_CRTC_EN)
335b7e1c893Smrg	    return TRUE;
336b7e1c893Smrg    } else {
337b7e1c893Smrg	reg = INREG(RADEON_CRTC_GEN_CNTL) | INREG(RADEON_CRTC2_GEN_CNTL);
338b7e1c893Smrg	if (reg & RADEON_CRTC_EN)
339b7e1c893Smrg	    return TRUE;
340b7e1c893Smrg    }
341b7e1c893Smrg
342c503f109Smrg    /* then check MEM_SIZE, in case something turned the crtcs off */
343c503f109Smrg    if (info->ChipFamily >= CHIP_FAMILY_R600)
344c503f109Smrg	reg = INREG(R600_CONFIG_MEMSIZE);
345c503f109Smrg    else
346c503f109Smrg	reg = INREG(RADEON_CONFIG_MEMSIZE);
347c503f109Smrg
348c503f109Smrg    if (reg)
349c503f109Smrg	return TRUE;
350c503f109Smrg
351b7e1c893Smrg    return FALSE;
352b7e1c893Smrg}
353b7e1c893Smrg
354209ff23fSmrg/* Read the Video BIOS block and the FP registers (if applicable). */
355209ff23fSmrgBool
356209ff23fSmrgRADEONGetBIOSInfo(ScrnInfoPtr pScrn, xf86Int10InfoPtr  pInt10)
357209ff23fSmrg{
358209ff23fSmrg    RADEONInfoPtr info     = RADEONPTR(pScrn);
359209ff23fSmrg    int tmp;
360209ff23fSmrg    unsigned short dptr;
361209ff23fSmrg
362209ff23fSmrg#ifdef XSERVER_LIBPCIACCESS
363209ff23fSmrg    int size = info->PciInfo->rom_size > RADEON_VBIOS_SIZE ? info->PciInfo->rom_size : RADEON_VBIOS_SIZE;
3642f39173dSmrg    info->VBIOS = malloc(size);
365209ff23fSmrg#else
3662f39173dSmrg    info->VBIOS = malloc(RADEON_VBIOS_SIZE);
367209ff23fSmrg#endif
368209ff23fSmrg    if (!info->VBIOS) {
369209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
370209ff23fSmrg		   "Cannot allocate space for hold Video BIOS!\n");
371209ff23fSmrg	return FALSE;
372209ff23fSmrg    } else {
373209ff23fSmrg	if (pInt10) {
374209ff23fSmrg	    info->BIOSAddr = pInt10->BIOSseg << 4;
375209ff23fSmrg	    (void)memcpy(info->VBIOS, xf86int10Addr(pInt10, info->BIOSAddr),
376209ff23fSmrg			 RADEON_VBIOS_SIZE);
377b7e1c893Smrg	} else if (!radeon_read_bios(pScrn))
378b7e1c893Smrg	    (void)radeon_read_disabled_bios(pScrn);
379209ff23fSmrg    }
380209ff23fSmrg
381209ff23fSmrg    if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) {
382209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
383209ff23fSmrg		   "Unrecognized BIOS signature, BIOS data will not be used\n");
3842f39173dSmrg	free (info->VBIOS);
385209ff23fSmrg	info->VBIOS = NULL;
386209ff23fSmrg	return FALSE;
387209ff23fSmrg    }
388209ff23fSmrg
389209ff23fSmrg    /* Verify it's an x86 BIOS not OF firmware, copied from radeonfb */
390209ff23fSmrg    dptr = RADEON_BIOS16(0x18);
391209ff23fSmrg    /* If PCI data signature is wrong assume x86 video BIOS anyway */
392209ff23fSmrg    if (RADEON_BIOS32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
393209ff23fSmrg       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
394209ff23fSmrg		   "ROM PCI data signature incorrect, ignoring\n");
395209ff23fSmrg    }
396209ff23fSmrg    else if (info->VBIOS[dptr + 0x14] != 0x0) {
397209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
398209ff23fSmrg		   "Not an x86 BIOS ROM image, BIOS data will not be used\n");
3992f39173dSmrg	free (info->VBIOS);
400209ff23fSmrg	info->VBIOS = NULL;
401209ff23fSmrg	return FALSE;
402209ff23fSmrg    }
403209ff23fSmrg
404209ff23fSmrg    if (info->VBIOS) info->ROMHeaderStart = RADEON_BIOS16(0x48);
405209ff23fSmrg
406209ff23fSmrg    if(!info->ROMHeaderStart) {
407209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
408209ff23fSmrg		   "Invalid ROM pointer, BIOS data will not be used\n");
4092f39173dSmrg	free (info->VBIOS);
410209ff23fSmrg	info->VBIOS = NULL;
411209ff23fSmrg	return FALSE;
412209ff23fSmrg    }
413b7e1c893Smrg
414209ff23fSmrg    tmp = info->ROMHeaderStart + 4;
415209ff23fSmrg    if ((RADEON_BIOS8(tmp)   == 'A' &&
416209ff23fSmrg	 RADEON_BIOS8(tmp+1) == 'T' &&
417209ff23fSmrg	 RADEON_BIOS8(tmp+2) == 'O' &&
418209ff23fSmrg	 RADEON_BIOS8(tmp+3) == 'M') ||
419209ff23fSmrg	(RADEON_BIOS8(tmp)   == 'M' &&
420209ff23fSmrg	 RADEON_BIOS8(tmp+1) == 'O' &&
421209ff23fSmrg	 RADEON_BIOS8(tmp+2) == 'T' &&
422209ff23fSmrg	 RADEON_BIOS8(tmp+3) == 'A'))
423209ff23fSmrg	info->IsAtomBios = TRUE;
424209ff23fSmrg    else
425209ff23fSmrg	info->IsAtomBios = FALSE;
426209ff23fSmrg
427209ff23fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s BIOS detected\n",
428209ff23fSmrg	       info->IsAtomBios ? "ATOM":"Legacy");
429209ff23fSmrg
430209ff23fSmrg    if (info->IsAtomBios) {
431b7e1c893Smrg	AtomBiosArgRec atomBiosArg;
432209ff23fSmrg
433b7e1c893Smrg	if (RHDAtomBiosFunc(pScrn->scrnIndex, NULL, ATOMBIOS_INIT, &atomBiosArg)
434b7e1c893Smrg	    == ATOM_SUCCESS) {
435b7e1c893Smrg	    info->atomBIOS = atomBiosArg.atomhandle;
436b7e1c893Smrg	}
437209ff23fSmrg
438b7e1c893Smrg	atomBiosArg.fb.start = info->FbFreeStart;
439b7e1c893Smrg	atomBiosArg.fb.size = info->FbFreeSize;
440b7e1c893Smrg	if (RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, ATOMBIOS_ALLOCATE_FB_SCRATCH,
441209ff23fSmrg			    &atomBiosArg) == ATOM_SUCCESS) {
442209ff23fSmrg
443209ff23fSmrg	    info->FbFreeStart = atomBiosArg.fb.start;
444209ff23fSmrg	    info->FbFreeSize = atomBiosArg.fb.size;
445b7e1c893Smrg	}
446b7e1c893Smrg
447b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, GET_DEFAULT_ENGINE_CLOCK,
448b7e1c893Smrg			&atomBiosArg);
449b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, GET_DEFAULT_MEMORY_CLOCK,
450b7e1c893Smrg			&atomBiosArg);
451b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
452b7e1c893Smrg			GET_MAX_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg);
453b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
454b7e1c893Smrg			GET_MIN_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg);
455b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
456b7e1c893Smrg			GET_MAX_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg);
457b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
458209ff23fSmrg			GET_MIN_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg);
459b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
460209ff23fSmrg			GET_MAX_PIXEL_CLK, &atomBiosArg);
461b7e1c893Smrg	RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
462b7e1c893Smrg			GET_REF_CLOCK, &atomBiosArg);
463209ff23fSmrg
464209ff23fSmrg	info->MasterDataStart = RADEON_BIOS16 (info->ROMHeaderStart + 32);
465209ff23fSmrg    }
466b7e1c893Smrg
467b7e1c893Smrg    /* We are a bit too quick at using this "unposted" to re-post the
468b7e1c893Smrg     * card. This causes some problems with VT switch on some machines,
469b7e1c893Smrg     * so let's work around this for now by only POSTing if none of the
470b7e1c893Smrg     * CRTCs are enabled
471b7e1c893Smrg     */
472b7e1c893Smrg    if ((!radeon_card_posted(pScrn)) && info->VBIOS) {
473b7e1c893Smrg	if (info->IsAtomBios) {
474b7e1c893Smrg	    if (!rhdAtomASICInit(info->atomBIOS))
475b7e1c893Smrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
476b7e1c893Smrg			   "%s: AsicInit failed.\n",__func__);
477b7e1c893Smrg	} else {
478209ff23fSmrg#if 0
479b7e1c893Smrg	    /* FIX ME */
480b7e1c893Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Attempting to POST via legacy BIOS tables\n");
481209ff23fSmrg	    RADEONGetBIOSInitTableOffsets(pScrn);
482209ff23fSmrg	    RADEONPostCardFromBIOSTables(pScrn);
483b7e1c893Smrg#endif
484209ff23fSmrg	}
485209ff23fSmrg    }
486b7e1c893Smrg
487209ff23fSmrg    return TRUE;
488209ff23fSmrg}
489209ff23fSmrg
490209ff23fSmrgstatic Bool RADEONGetATOMConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
491209ff23fSmrg{
492209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
493209ff23fSmrg
494209ff23fSmrg    if (!info->VBIOS) return FALSE;
495b7e1c893Smrg
496209ff23fSmrg    if (RADEONGetATOMConnectorInfoFromBIOSObject(pScrn))
497209ff23fSmrg	return TRUE;
498209ff23fSmrg
499209ff23fSmrg    if (RADEONGetATOMConnectorInfoFromBIOSConnectorTable(pScrn))
500209ff23fSmrg	return TRUE;
501209ff23fSmrg
502209ff23fSmrg    return FALSE;
503209ff23fSmrg}
504209ff23fSmrg
505209ff23fSmrgstatic void RADEONApplyLegacyQuirks(ScrnInfoPtr pScrn, int index)
506209ff23fSmrg{
507209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
508209ff23fSmrg
509b7e1c893Smrg    /* XPRESS DDC quirks */
510209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400 ||
511209ff23fSmrg	 info->ChipFamily == CHIP_FAMILY_RS480) &&
512209ff23fSmrg	info->BiosConnector[index].ddc_i2c.mask_clk_reg == RADEON_GPIO_CRT2_DDC) {
513209ff23fSmrg	info->BiosConnector[index].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID);
514b7e1c893Smrg    } else if ((info->ChipFamily == CHIP_FAMILY_RS400 ||
515b7e1c893Smrg		info->ChipFamily == CHIP_FAMILY_RS480) &&
516b7e1c893Smrg	       info->BiosConnector[index].ddc_i2c.mask_clk_reg == RADEON_GPIO_MONID) {
517b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.valid = TRUE;
518b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.mask_clk_mask = (0x20 << 8);
519b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.mask_data_mask = 0x80;
520b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.a_clk_mask = (0x20 << 8);
521b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.a_data_mask = 0x80;
522b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.put_clk_mask = (0x20 << 8);
523b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.put_data_mask = 0x80;
524b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.get_clk_mask = (0x20 << 8);
525b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.get_data_mask = 0x80;
526b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.mask_clk_reg = RADEON_GPIOPAD_MASK;
527b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.mask_data_reg = RADEON_GPIOPAD_MASK;
528b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.a_clk_reg = RADEON_GPIOPAD_A;
529b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.a_data_reg = RADEON_GPIOPAD_A;
530b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.put_clk_reg = RADEON_GPIOPAD_EN;
531b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.put_data_reg = RADEON_GPIOPAD_EN;
532b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.get_clk_reg = RADEON_LCD_GPIO_Y_REG;
533b7e1c893Smrg	info->BiosConnector[index].ddc_i2c.get_data_reg = RADEON_LCD_GPIO_Y_REG;
534209ff23fSmrg    }
535209ff23fSmrg
536ad43ddacSmrg    /* R3xx+ chips don't have GPIO_CRT2_DDC gpio pad */
537ad43ddacSmrg    if ((IS_R300_VARIANT) &&
538ad43ddacSmrg	info->BiosConnector[index].ddc_i2c.mask_clk_reg == RADEON_GPIO_CRT2_DDC)
539ad43ddacSmrg	info->BiosConnector[index].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
540ad43ddacSmrg
541209ff23fSmrg    /* Certain IBM chipset RN50s have a BIOS reporting two VGAs,
542209ff23fSmrg       one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */
543209ff23fSmrg    if (info->Chipset == PCI_CHIP_RN50_515E &&
544209ff23fSmrg	PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1014) {
545209ff23fSmrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_VGA &&
546209ff23fSmrg	    info->BiosConnector[index].ddc_i2c.mask_clk_reg == RADEON_GPIO_CRT2_DDC) {
547209ff23fSmrg	    info->BiosConnector[index].valid = FALSE;
548209ff23fSmrg	}
549209ff23fSmrg    }
550209ff23fSmrg
551b7e1c893Smrg    /* X300 card with extra non-existent DVI port */
552b7e1c893Smrg    if (info->Chipset == PCI_CHIP_RV370_5B60 &&
553b7e1c893Smrg	PCI_SUB_VENDOR_ID(info->PciInfo) == 0x17af &&
554b7e1c893Smrg	PCI_SUB_DEVICE_ID(info->PciInfo) == 0x201e &&
555b7e1c893Smrg	index == 2) {
556b7e1c893Smrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_DVI_I) {
557b7e1c893Smrg	    info->BiosConnector[index].valid = FALSE;
558b7e1c893Smrg	}
559b7e1c893Smrg    }
560b7e1c893Smrg
561b7e1c893Smrg    /* r200 card with primary dac routed to both VGA and DVI - disable load detection
562b7e1c893Smrg     * otherwise you end up detecing load if either port is attached
563b7e1c893Smrg     */
564b7e1c893Smrg    if (info->Chipset == PCI_CHIP_R200_QL &&
565b7e1c893Smrg	PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1569 &&
566b7e1c893Smrg	PCI_SUB_DEVICE_ID(info->PciInfo) == 0x514c &&
567b7e1c893Smrg	(info->BiosConnector[index].devices & ATOM_DEVICE_CRT1_SUPPORT)) {
568b7e1c893Smrg	info->BiosConnector[index].load_detection = FALSE;
569b7e1c893Smrg    }
570b7e1c893Smrg
571209ff23fSmrg}
572209ff23fSmrg
573209ff23fSmrgstatic Bool RADEONGetLegacyConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
574209ff23fSmrg{
575209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
576209ff23fSmrg    int offset, i, entry, tmp, tmp0, tmp1;
577209ff23fSmrg    RADEONLegacyDDCType DDCType;
578209ff23fSmrg    RADEONLegacyConnectorType ConnectorType;
579209ff23fSmrg
580209ff23fSmrg    if (!info->VBIOS) return FALSE;
581209ff23fSmrg
582209ff23fSmrg    offset = RADEON_BIOS16(info->ROMHeaderStart + 0x50);
583209ff23fSmrg    if (offset) {
584209ff23fSmrg	for (i = 0; i < 4; i++) {
585209ff23fSmrg	    entry = offset + 2 + i*2;
586209ff23fSmrg
587209ff23fSmrg	    if (!RADEON_BIOS16(entry)) {
588209ff23fSmrg		break;
589209ff23fSmrg	    }
590209ff23fSmrg	    info->BiosConnector[i].valid = TRUE;
591209ff23fSmrg	    tmp = RADEON_BIOS16(entry);
592209ff23fSmrg	    info->BiosConnector[i].ConnectorType = (tmp >> 12) & 0xf;
593209ff23fSmrg	    ConnectorType = (tmp >> 12) & 0xf;
594209ff23fSmrg	    switch (ConnectorType) {
595209ff23fSmrg	    case CONNECTOR_PROPRIETARY_LEGACY:
596b7e1c893Smrg		info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_D;
597b7e1c893Smrg		if ((tmp >> 4) & 0x1) {
598b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP2_SUPPORT;
599b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
600b7e1c893Smrg				       radeon_get_encoder_id_from_supported_device(pScrn,
601b7e1c893Smrg										   ATOM_DEVICE_DFP2_SUPPORT,
602b7e1c893Smrg										   0),
603b7e1c893Smrg					    ATOM_DEVICE_DFP2_SUPPORT))
604b7e1c893Smrg			return FALSE;
605b7e1c893Smrg		} else {
606b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP1_SUPPORT;
607b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
608b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
609b7e1c893Smrg											ATOM_DEVICE_DFP1_SUPPORT,
610b7e1c893Smrg											0),
611b7e1c893Smrg					    ATOM_DEVICE_DFP1_SUPPORT))
612b7e1c893Smrg			return FALSE;
613b7e1c893Smrg		}
614209ff23fSmrg		break;
615209ff23fSmrg	    case CONNECTOR_CRT_LEGACY:
616209ff23fSmrg		info->BiosConnector[i].ConnectorType = CONNECTOR_VGA;
617b7e1c893Smrg		if (tmp & 0x1) {
618b7e1c893Smrg		    info->BiosConnector[i].load_detection = FALSE;
619b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_CRT2_SUPPORT;
620b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
621b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
622b7e1c893Smrg											ATOM_DEVICE_CRT2_SUPPORT,
623b7e1c893Smrg											2),
624b7e1c893Smrg					    ATOM_DEVICE_CRT2_SUPPORT))
625b7e1c893Smrg			return FALSE;
626b7e1c893Smrg		} else {
627b7e1c893Smrg		    info->BiosConnector[i].load_detection = TRUE;
628b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_CRT1_SUPPORT;
629b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
630b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
631b7e1c893Smrg											ATOM_DEVICE_CRT1_SUPPORT,
632b7e1c893Smrg											1),
633b7e1c893Smrg					    ATOM_DEVICE_CRT1_SUPPORT))
634b7e1c893Smrg			return FALSE;
635b7e1c893Smrg		}
636209ff23fSmrg		break;
637209ff23fSmrg	    case CONNECTOR_DVI_I_LEGACY:
638209ff23fSmrg		info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_I;
639b7e1c893Smrg		if (tmp & 0x1) {
640b7e1c893Smrg		    info->BiosConnector[i].load_detection = FALSE;
641b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_CRT2_SUPPORT;
642b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
643b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
644b7e1c893Smrg											ATOM_DEVICE_CRT2_SUPPORT,
645b7e1c893Smrg											2),
646b7e1c893Smrg					    ATOM_DEVICE_CRT2_SUPPORT))
647b7e1c893Smrg			return FALSE;
648b7e1c893Smrg		} else {
649b7e1c893Smrg		    info->BiosConnector[i].load_detection = TRUE;
650b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_CRT1_SUPPORT;
651b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
652b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
653b7e1c893Smrg											ATOM_DEVICE_CRT1_SUPPORT,
654b7e1c893Smrg											1),
655b7e1c893Smrg					    ATOM_DEVICE_CRT1_SUPPORT))
656b7e1c893Smrg			return FALSE;
657b7e1c893Smrg		}
658b7e1c893Smrg		if ((tmp >> 4) & 0x1) {
659b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP2_SUPPORT;
660b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
661b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
662b7e1c893Smrg											ATOM_DEVICE_DFP2_SUPPORT,
663b7e1c893Smrg											0),
664b7e1c893Smrg					    ATOM_DEVICE_DFP2_SUPPORT))
665b7e1c893Smrg			return FALSE;
666b7e1c893Smrg		} else {
667b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP1_SUPPORT;
668b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
669b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
670b7e1c893Smrg											ATOM_DEVICE_DFP1_SUPPORT,
671b7e1c893Smrg											0),
672b7e1c893Smrg					    ATOM_DEVICE_DFP1_SUPPORT))
673b7e1c893Smrg			return FALSE;
674b7e1c893Smrg		}
675209ff23fSmrg		break;
676209ff23fSmrg	    case CONNECTOR_DVI_D_LEGACY:
677209ff23fSmrg		info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_D;
678b7e1c893Smrg		if ((tmp >> 4) & 0x1) {
679b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP2_SUPPORT;
680b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
681b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
682b7e1c893Smrg											ATOM_DEVICE_DFP2_SUPPORT,
683b7e1c893Smrg											0),
684b7e1c893Smrg					    ATOM_DEVICE_DFP2_SUPPORT))
685b7e1c893Smrg			return FALSE;
686b7e1c893Smrg		} else {
687b7e1c893Smrg		    info->BiosConnector[i].devices |= ATOM_DEVICE_DFP1_SUPPORT;
688b7e1c893Smrg		    if (!radeon_add_encoder(pScrn,
689b7e1c893Smrg					    radeon_get_encoder_id_from_supported_device(pScrn,
690b7e1c893Smrg											ATOM_DEVICE_DFP1_SUPPORT,
691b7e1c893Smrg											0),
692b7e1c893Smrg					    ATOM_DEVICE_DFP1_SUPPORT))
693b7e1c893Smrg			return FALSE;
694b7e1c893Smrg		}
695209ff23fSmrg		break;
696209ff23fSmrg	    case CONNECTOR_CTV_LEGACY:
697209ff23fSmrg		info->BiosConnector[i].ConnectorType = CONNECTOR_CTV;
698b7e1c893Smrg		info->BiosConnector[i].load_detection = FALSE;
699b7e1c893Smrg		info->BiosConnector[i].devices = ATOM_DEVICE_TV1_SUPPORT;
700b7e1c893Smrg		if (!radeon_add_encoder(pScrn,
701b7e1c893Smrg					radeon_get_encoder_id_from_supported_device(pScrn,
702b7e1c893Smrg										    ATOM_DEVICE_TV1_SUPPORT,
703b7e1c893Smrg										    2),
704b7e1c893Smrg					ATOM_DEVICE_TV1_SUPPORT))
705b7e1c893Smrg		    return FALSE;
706209ff23fSmrg		break;
707209ff23fSmrg	    case CONNECTOR_STV_LEGACY:
708209ff23fSmrg		info->BiosConnector[i].ConnectorType = CONNECTOR_STV;
709b7e1c893Smrg		info->BiosConnector[i].load_detection = FALSE;
710b7e1c893Smrg		info->BiosConnector[i].devices = ATOM_DEVICE_TV1_SUPPORT;
711b7e1c893Smrg		if (!radeon_add_encoder(pScrn,
712b7e1c893Smrg					radeon_get_encoder_id_from_supported_device(pScrn,
713b7e1c893Smrg										    ATOM_DEVICE_TV1_SUPPORT,
714b7e1c893Smrg										    2),
715b7e1c893Smrg					ATOM_DEVICE_TV1_SUPPORT))
716b7e1c893Smrg		    return FALSE;
717209ff23fSmrg		break;
718209ff23fSmrg	    default:
719209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown Connector Type: %d\n", ConnectorType);
720209ff23fSmrg		info->BiosConnector[i].valid = FALSE;
721209ff23fSmrg		break;
722209ff23fSmrg	    }
723209ff23fSmrg
724209ff23fSmrg	    info->BiosConnector[i].ddc_i2c.valid = FALSE;
725209ff23fSmrg
726209ff23fSmrg	    DDCType = (tmp >> 8) & 0xf;
727209ff23fSmrg	    switch (DDCType) {
728209ff23fSmrg	    case DDC_MONID:
729209ff23fSmrg		info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID);
730209ff23fSmrg		break;
731209ff23fSmrg	    case DDC_DVI:
732209ff23fSmrg		info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
733209ff23fSmrg		break;
734209ff23fSmrg	    case DDC_VGA:
735209ff23fSmrg		info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
736209ff23fSmrg		break;
737209ff23fSmrg	    case DDC_CRT2:
738209ff23fSmrg		info->BiosConnector[i].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
739209ff23fSmrg		break;
740209ff23fSmrg	    default:
741209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown DDC Type: %d\n", DDCType);
742209ff23fSmrg		break;
743209ff23fSmrg	    }
744209ff23fSmrg
745209ff23fSmrg	    RADEONApplyLegacyQuirks(pScrn, i);
746209ff23fSmrg
747209ff23fSmrg	}
748209ff23fSmrg    } else {
749209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Connector Info Table found!\n");
750209ff23fSmrg
751209ff23fSmrg	/* old radeons and r128 didn't use connector tables you just check
752209ff23fSmrg	 * for LVDS, DVI, TV, etc. tables
753209ff23fSmrg	 */
754209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x34);
755209ff23fSmrg	if (offset) {
756209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
757209ff23fSmrg		       "Found DFP table, assuming DVI connector\n");
758209ff23fSmrg	    info->BiosConnector[0].valid = TRUE;
759209ff23fSmrg	    info->BiosConnector[0].ConnectorType = CONNECTOR_DVI_I;
760b7e1c893Smrg	    info->BiosConnector[0].load_detection = TRUE;
761209ff23fSmrg	    info->BiosConnector[0].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
762b7e1c893Smrg	    info->BiosConnector[0].devices = ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_DFP1_SUPPORT;
763b7e1c893Smrg	    if (!radeon_add_encoder(pScrn,
764b7e1c893Smrg				    radeon_get_encoder_id_from_supported_device(pScrn,
765b7e1c893Smrg										ATOM_DEVICE_DFP1_SUPPORT,
766b7e1c893Smrg										0),
767b7e1c893Smrg				    ATOM_DEVICE_DFP1_SUPPORT))
768b7e1c893Smrg		return FALSE;
769b7e1c893Smrg	    if (!radeon_add_encoder(pScrn,
770b7e1c893Smrg				    radeon_get_encoder_id_from_supported_device(pScrn,
771b7e1c893Smrg										ATOM_DEVICE_CRT1_SUPPORT,
772b7e1c893Smrg										1),
773b7e1c893Smrg				    ATOM_DEVICE_CRT1_SUPPORT))
774b7e1c893Smrg		return FALSE;
775209ff23fSmrg	} else
776209ff23fSmrg	    return FALSE;
777209ff23fSmrg    }
778209ff23fSmrg
779209ff23fSmrg    /* check LVDS table */
780b7e1c893Smrg    /* IGP can be mobile or desktop so check the connectors */
781b7e1c893Smrg    if (info->IsMobility || info->IsIGP) {
782209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x40);
783209ff23fSmrg	if (offset) {
784209ff23fSmrg	    info->BiosConnector[4].valid = TRUE;
785209ff23fSmrg	    info->BiosConnector[4].ConnectorType = CONNECTOR_LVDS;
786209ff23fSmrg	    info->BiosConnector[4].ddc_i2c.valid = FALSE;
787209ff23fSmrg
788b7e1c893Smrg	    info->BiosConnector[4].devices = ATOM_DEVICE_LCD1_SUPPORT;
789b7e1c893Smrg	    if (!radeon_add_encoder(pScrn,
790b7e1c893Smrg				    radeon_get_encoder_id_from_supported_device(pScrn,
791b7e1c893Smrg										ATOM_DEVICE_LCD1_SUPPORT,
792b7e1c893Smrg										0),
793b7e1c893Smrg				    ATOM_DEVICE_LCD1_SUPPORT))
794b7e1c893Smrg		return FALSE;
795b7e1c893Smrg
796209ff23fSmrg	    tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x42);
797209ff23fSmrg	    if (tmp) {
798209ff23fSmrg		tmp0 = RADEON_BIOS16(tmp + 0x15);
799209ff23fSmrg		if (tmp0) {
800209ff23fSmrg		    tmp1 = RADEON_BIOS8(tmp0+2) & 0x07;
801209ff23fSmrg		    if (tmp1) {
802209ff23fSmrg			DDCType	= tmp1;
803209ff23fSmrg			switch (DDCType) {
804b7e1c893Smrg			case DDC_NONE_DETECTED:
805b7e1c893Smrg			    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No DDC for LCD\n");
806b7e1c893Smrg			    break;
807209ff23fSmrg			case DDC_MONID:
808209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID);
809209ff23fSmrg			    break;
810209ff23fSmrg			case DDC_DVI:
811209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
812209ff23fSmrg			    break;
813209ff23fSmrg			case DDC_VGA:
814209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
815209ff23fSmrg			    break;
816209ff23fSmrg			case DDC_CRT2:
817209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
818209ff23fSmrg			    break;
819209ff23fSmrg			case DDC_LCD:
820209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_LCD_GPIO_MASK);
821b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.mask_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
822b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.mask_data_mask = RADEON_BIOS32(tmp0 + 0x07);
823b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.a_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
824b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.a_data_mask = RADEON_BIOS32(tmp0 + 0x07);
825209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.put_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
826209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.put_data_mask = RADEON_BIOS32(tmp0 + 0x07);
827209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.get_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
828209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.get_data_mask = RADEON_BIOS32(tmp0 + 0x07);
829209ff23fSmrg			    break;
830209ff23fSmrg			case DDC_GPIO:
831209ff23fSmrg			    info->BiosConnector[4].ddc_i2c = legacy_setup_i2c_bus(RADEON_MDGPIO_EN_REG);
832b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.mask_clk_mask =  RADEON_BIOS32(tmp0 + 0x03);
833b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.mask_data_mask = RADEON_BIOS32(tmp0 + 0x07);
834b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.a_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
835b7e1c893Smrg			    info->BiosConnector[4].ddc_i2c.a_data_mask = RADEON_BIOS32(tmp0 + 0x07);
836209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.put_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
837209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.put_data_mask = RADEON_BIOS32(tmp0 + 0x07);
838209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.get_clk_mask = RADEON_BIOS32(tmp0 + 0x03);
839209ff23fSmrg			    info->BiosConnector[4].ddc_i2c.get_data_mask = RADEON_BIOS32(tmp0 + 0x07);
840209ff23fSmrg			    break;
841209ff23fSmrg			default:
842209ff23fSmrg			    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown DDC Type: %d\n", DDCType);
843209ff23fSmrg			    break;
844209ff23fSmrg			}
845209ff23fSmrg			xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "LCD DDC Info Table found!\n");
846209ff23fSmrg		    }
847209ff23fSmrg		}
848b7e1c893Smrg	    } else
849209ff23fSmrg		info->BiosConnector[4].ddc_i2c.valid = FALSE;
850209ff23fSmrg	}
851209ff23fSmrg    }
852209ff23fSmrg
853209ff23fSmrg    /* check TV table */
854209ff23fSmrg    if (info->InternalTVOut) {
855209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32);
856209ff23fSmrg	if (offset) {
857209ff23fSmrg	    if (RADEON_BIOS8(offset + 6) == 'T') {
858209ff23fSmrg		info->BiosConnector[5].valid = TRUE;
859209ff23fSmrg		/* assume s-video for now */
860209ff23fSmrg		info->BiosConnector[5].ConnectorType = CONNECTOR_STV;
861b7e1c893Smrg		info->BiosConnector[5].load_detection = FALSE;
862209ff23fSmrg		info->BiosConnector[5].ddc_i2c.valid = FALSE;
863b7e1c893Smrg		info->BiosConnector[5].devices = ATOM_DEVICE_TV1_SUPPORT;
864b7e1c893Smrg		if (!radeon_add_encoder(pScrn,
865b7e1c893Smrg					radeon_get_encoder_id_from_supported_device(pScrn,
866b7e1c893Smrg										    ATOM_DEVICE_TV1_SUPPORT,
867b7e1c893Smrg										    2),
868b7e1c893Smrg					ATOM_DEVICE_TV1_SUPPORT))
869b7e1c893Smrg		    return FALSE;
870209ff23fSmrg	    }
871209ff23fSmrg	}
872209ff23fSmrg    }
873209ff23fSmrg
874209ff23fSmrg    return TRUE;
875209ff23fSmrg}
876209ff23fSmrg
877209ff23fSmrgBool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
878209ff23fSmrg{
879209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
880209ff23fSmrg
881209ff23fSmrg    if(!info->VBIOS) return FALSE;
882209ff23fSmrg
883209ff23fSmrg    if (info->IsAtomBios)
884209ff23fSmrg	return RADEONGetATOMConnectorInfoFromBIOS(pScrn);
885209ff23fSmrg    else
886209ff23fSmrg	return RADEONGetLegacyConnectorInfoFromBIOS(pScrn);
887209ff23fSmrg}
888209ff23fSmrg
889209ff23fSmrgBool RADEONGetTVInfoFromBIOS (xf86OutputPtr output) {
890209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
891209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
892209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
893b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
894209ff23fSmrg    int offset, refclk, stds;
895209ff23fSmrg
896209ff23fSmrg    if (!info->VBIOS) return FALSE;
897209ff23fSmrg
898b7e1c893Smrg    if (info->IsAtomBios)
899209ff23fSmrg        return RADEONGetATOMTVInfo(output);
900b7e1c893Smrg    else {
901209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32);
902209ff23fSmrg	if (offset) {
903209ff23fSmrg	    if (RADEON_BIOS8(offset + 6) == 'T') {
904209ff23fSmrg		switch (RADEON_BIOS8(offset + 7) & 0xf) {
905209ff23fSmrg		case 1:
906b7e1c893Smrg		    tvout->default_tvStd = TV_STD_NTSC;
907209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC\n");
908209ff23fSmrg		    break;
909209ff23fSmrg		case 2:
910b7e1c893Smrg		    tvout->default_tvStd = TV_STD_PAL;
911209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL\n");
912209ff23fSmrg		    break;
913209ff23fSmrg		case 3:
914b7e1c893Smrg		    tvout->default_tvStd = TV_STD_PAL_M;
915209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-M\n");
916209ff23fSmrg		    break;
917209ff23fSmrg		case 4:
918b7e1c893Smrg		    tvout->default_tvStd = TV_STD_PAL_60;
919209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-60\n");
920209ff23fSmrg		    break;
921209ff23fSmrg		case 5:
922b7e1c893Smrg		    tvout->default_tvStd = TV_STD_NTSC_J;
923209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC-J\n");
924209ff23fSmrg		    break;
925209ff23fSmrg		case 6:
926b7e1c893Smrg		    tvout->default_tvStd = TV_STD_SCART_PAL;
927209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: SCART-PAL\n");
928209ff23fSmrg		    break;
929209ff23fSmrg		default:
930b7e1c893Smrg		    tvout->default_tvStd = TV_STD_NTSC;
931209ff23fSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Unknown TV standard; defaulting to NTSC\n");
932209ff23fSmrg		    break;
933209ff23fSmrg		}
934b7e1c893Smrg		tvout->tvStd = tvout->default_tvStd;
935209ff23fSmrg
936209ff23fSmrg		refclk = (RADEON_BIOS8(offset + 9) >> 2) & 0x3;
937209ff23fSmrg		if (refclk == 0)
938b7e1c893Smrg		    tvout->TVRefClk = 29.498928713; /* MHz */
939209ff23fSmrg		else if (refclk == 1)
940b7e1c893Smrg		    tvout->TVRefClk = 28.636360000;
941209ff23fSmrg		else if (refclk == 2)
942b7e1c893Smrg		    tvout->TVRefClk = 14.318180000;
943209ff23fSmrg		else if (refclk == 3)
944b7e1c893Smrg		    tvout->TVRefClk = 27.000000000;
945209ff23fSmrg
946b7e1c893Smrg		tvout->SupportedTVStds = tvout->default_tvStd;
947209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standards supported by chip: ");
948209ff23fSmrg		stds = RADEON_BIOS8(offset + 10) & 0x1f;
949209ff23fSmrg		if (stds & TV_STD_NTSC) {
950b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_NTSC;
951209ff23fSmrg		    ErrorF("NTSC ");
952209ff23fSmrg		}
953209ff23fSmrg		if (stds & TV_STD_PAL) {
954b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_PAL;
955209ff23fSmrg		    ErrorF("PAL ");
956209ff23fSmrg		}
957209ff23fSmrg		if (stds & TV_STD_PAL_M) {
958b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_PAL_M;
959209ff23fSmrg		    ErrorF("PAL-M ");
960209ff23fSmrg		}
961209ff23fSmrg		if (stds & TV_STD_PAL_60) {
962b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_PAL_60;
963209ff23fSmrg		    ErrorF("PAL-60 ");
964209ff23fSmrg		}
965209ff23fSmrg		if (stds & TV_STD_NTSC_J) {
966b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_NTSC_J;
967209ff23fSmrg		    ErrorF("NTSC-J ");
968209ff23fSmrg		}
969209ff23fSmrg		if (stds & TV_STD_SCART_PAL) {
970b7e1c893Smrg		    tvout->SupportedTVStds |= TV_STD_SCART_PAL;
971209ff23fSmrg		    ErrorF("SCART-PAL");
972209ff23fSmrg		}
973209ff23fSmrg		ErrorF("\n");
974209ff23fSmrg
975209ff23fSmrg		return TRUE;
976209ff23fSmrg	    }
977209ff23fSmrg	}
978209ff23fSmrg    }
979209ff23fSmrg    return FALSE;
980209ff23fSmrg}
981209ff23fSmrg
982209ff23fSmrg/* Read PLL parameters from BIOS block.  Default to typical values if there
983209ff23fSmrg   is no BIOS. */
984209ff23fSmrgBool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn)
985209ff23fSmrg{
986209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
987209ff23fSmrg    RADEONPLLPtr pll = &info->pll;
988209ff23fSmrg    uint16_t pll_info_block;
989209ff23fSmrg
990209ff23fSmrg    if (!info->VBIOS) {
991209ff23fSmrg	return FALSE;
992209ff23fSmrg    } else {
993209ff23fSmrg	if (info->IsAtomBios) {
994ad43ddacSmrg	    return RADEONGetATOMClockInfo(pScrn);
995209ff23fSmrg	} else {
996209ff23fSmrg	    int rev;
997209ff23fSmrg
998209ff23fSmrg	    pll_info_block = RADEON_BIOS16 (info->ROMHeaderStart + 0x30);
999209ff23fSmrg
1000209ff23fSmrg	    rev = RADEON_BIOS8(pll_info_block);
1001209ff23fSmrg
1002209ff23fSmrg	    pll->reference_freq = RADEON_BIOS16 (pll_info_block + 0x0e);
1003209ff23fSmrg	    pll->reference_div = RADEON_BIOS16 (pll_info_block + 0x10);
1004209ff23fSmrg	    pll->pll_out_min = RADEON_BIOS32 (pll_info_block + 0x12);
1005209ff23fSmrg	    pll->pll_out_max = RADEON_BIOS32 (pll_info_block + 0x16);
1006209ff23fSmrg
1007209ff23fSmrg	    if (rev > 9) {
1008209ff23fSmrg		pll->pll_in_min = RADEON_BIOS32(pll_info_block + 0x36);
1009209ff23fSmrg		pll->pll_in_max = RADEON_BIOS32(pll_info_block + 0x3a);
1010209ff23fSmrg	    } else {
1011209ff23fSmrg		pll->pll_in_min = 40;
1012209ff23fSmrg		pll->pll_in_max = 500;
1013209ff23fSmrg	    }
1014209ff23fSmrg
1015209ff23fSmrg	    pll->xclk = RADEON_BIOS16(pll_info_block + 0x08);
1016209ff23fSmrg
1017b7e1c893Smrg	    info->sclk = RADEON_BIOS16(pll_info_block + 10) / 100.0;
1018b7e1c893Smrg	    info->mclk = RADEON_BIOS16(pll_info_block + 8) / 100.0;
1019209ff23fSmrg	}
1020209ff23fSmrg
1021209ff23fSmrg	if (info->sclk == 0) info->sclk = 200;
1022209ff23fSmrg	if (info->mclk == 0) info->mclk = 200;
1023209ff23fSmrg    }
1024209ff23fSmrg
1025209ff23fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ref_freq: %d, min_out_pll: %u, "
1026209ff23fSmrg	       "max_out_pll: %u, min_in_pll: %u, max_in_pll: %u, xclk: %d, "
1027209ff23fSmrg	       "sclk: %f, mclk: %f\n",
1028209ff23fSmrg	       pll->reference_freq, (unsigned)pll->pll_out_min,
1029209ff23fSmrg	       (unsigned)pll->pll_out_max, (unsigned)pll->pll_in_min,
1030209ff23fSmrg	       (unsigned)pll->pll_in_max, pll->xclk, info->sclk, info->mclk);
1031209ff23fSmrg
1032209ff23fSmrg    return TRUE;
1033209ff23fSmrg}
1034209ff23fSmrg
1035b7e1c893SmrgBool RADEONGetDAC2InfoFromBIOS (ScrnInfoPtr pScrn, radeon_tvdac_ptr tvdac)
1036209ff23fSmrg{
1037209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1038209ff23fSmrg    int offset, rev, bg, dac;
1039209ff23fSmrg
1040209ff23fSmrg    if (!info->VBIOS) return FALSE;
1041209ff23fSmrg
1042209ff23fSmrg    if (xf86ReturnOptValBool(info->Options, OPTION_DEFAULT_TVDAC_ADJ, FALSE))
1043209ff23fSmrg	return FALSE;
1044209ff23fSmrg
1045209ff23fSmrg    if (info->IsAtomBios) {
1046209ff23fSmrg	/* not implemented yet */
1047209ff23fSmrg	return FALSE;
1048209ff23fSmrg    } else {
1049209ff23fSmrg	/* first check TV table */
1050209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32);
1051209ff23fSmrg        if (offset) {
1052209ff23fSmrg	    rev = RADEON_BIOS8(offset + 0x3);
1053209ff23fSmrg	    if (rev > 4) {
1054209ff23fSmrg		bg = RADEON_BIOS8(offset + 0xc) & 0xf;
1055209ff23fSmrg		dac = RADEON_BIOS8(offset + 0xd) & 0xf;
1056b7e1c893Smrg		tvdac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1057209ff23fSmrg
1058209ff23fSmrg		bg = RADEON_BIOS8(offset + 0xe) & 0xf;
1059209ff23fSmrg		dac = RADEON_BIOS8(offset + 0xf) & 0xf;
1060b7e1c893Smrg		tvdac->pal_tvdac_adj = (bg << 16) | (dac << 20);
1061209ff23fSmrg
1062209ff23fSmrg		bg = RADEON_BIOS8(offset + 0x10) & 0xf;
1063209ff23fSmrg		dac = RADEON_BIOS8(offset + 0x11) & 0xf;
1064b7e1c893Smrg		tvdac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
1065209ff23fSmrg
1066209ff23fSmrg		return TRUE;
1067209ff23fSmrg	    } else if (rev > 1) {
1068209ff23fSmrg		bg = RADEON_BIOS8(offset + 0xc) & 0xf;
1069209ff23fSmrg		dac = (RADEON_BIOS8(offset + 0xc) >> 4) & 0xf;
1070b7e1c893Smrg		tvdac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1071209ff23fSmrg
1072209ff23fSmrg		bg = RADEON_BIOS8(offset + 0xd) & 0xf;
1073209ff23fSmrg		dac = (RADEON_BIOS8(offset + 0xd) >> 4) & 0xf;
1074b7e1c893Smrg		tvdac->pal_tvdac_adj = (bg << 16) | (dac << 20);
1075209ff23fSmrg
1076209ff23fSmrg		bg = RADEON_BIOS8(offset + 0xe) & 0xf;
1077209ff23fSmrg		dac = (RADEON_BIOS8(offset + 0xe) >> 4) & 0xf;
1078b7e1c893Smrg		tvdac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
1079209ff23fSmrg
1080209ff23fSmrg		return TRUE;
1081209ff23fSmrg	    }
1082209ff23fSmrg	}
1083209ff23fSmrg	/* then check CRT table */
1084209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x60);
1085209ff23fSmrg        if (offset) {
1086209ff23fSmrg	    rev = RADEON_BIOS8(offset) & 0x3;
1087209ff23fSmrg	    if (rev < 2) {
1088209ff23fSmrg		bg = RADEON_BIOS8(offset + 0x3) & 0xf;
1089209ff23fSmrg		dac = (RADEON_BIOS8(offset + 0x3) >> 4) & 0xf;
1090b7e1c893Smrg		tvdac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1091b7e1c893Smrg		tvdac->pal_tvdac_adj = tvdac->ps2_tvdac_adj;
1092b7e1c893Smrg		tvdac->ntsc_tvdac_adj = tvdac->ps2_tvdac_adj;
1093209ff23fSmrg
1094209ff23fSmrg		return TRUE;
1095209ff23fSmrg	    } else {
1096209ff23fSmrg		bg = RADEON_BIOS8(offset + 0x4) & 0xf;
1097209ff23fSmrg		dac = RADEON_BIOS8(offset + 0x5) & 0xf;
1098b7e1c893Smrg		tvdac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1099b7e1c893Smrg		tvdac->pal_tvdac_adj = tvdac->ps2_tvdac_adj;
1100b7e1c893Smrg		tvdac->ntsc_tvdac_adj = tvdac->ps2_tvdac_adj;
1101209ff23fSmrg
1102209ff23fSmrg		return TRUE;
1103209ff23fSmrg	    }
1104209ff23fSmrg	}
1105209ff23fSmrg    }
1106209ff23fSmrg
1107209ff23fSmrg    return FALSE;
1108209ff23fSmrg}
1109209ff23fSmrg
1110b7e1c893SmrgBool
1111b7e1c893SmrgRADEONGetLVDSInfoFromBIOS(ScrnInfoPtr pScrn, radeon_lvds_ptr lvds)
1112209ff23fSmrg{
1113209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1114b7e1c893Smrg    radeon_native_mode_ptr native_mode = &lvds->native_mode;
1115209ff23fSmrg    unsigned long tmp, i;
1116209ff23fSmrg
1117b7e1c893Smrg    if (!info->VBIOS)
1118b7e1c893Smrg	return FALSE;
1119209ff23fSmrg
1120b7e1c893Smrg    if (!info->IsAtomBios) {
1121209ff23fSmrg	tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x40);
1122209ff23fSmrg
1123209ff23fSmrg	if (!tmp) {
1124209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1125209ff23fSmrg		       "No Panel Info Table found in BIOS!\n");
1126209ff23fSmrg	    return FALSE;
1127209ff23fSmrg	} else {
1128209ff23fSmrg	    char  stmp[30];
1129209ff23fSmrg	    int   tmp0;
1130209ff23fSmrg
1131209ff23fSmrg	    for (i = 0; i < 24; i++)
1132209ff23fSmrg	    stmp[i] = RADEON_BIOS8(tmp+i+1);
1133209ff23fSmrg	    stmp[24] = 0;
1134209ff23fSmrg
1135209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1136209ff23fSmrg		       "Panel ID string: %s\n", stmp);
1137209ff23fSmrg
1138b7e1c893Smrg	    native_mode->PanelXRes = RADEON_BIOS16(tmp+25);
1139b7e1c893Smrg	    native_mode->PanelYRes = RADEON_BIOS16(tmp+27);
1140209ff23fSmrg	    xf86DrvMsg(0, X_INFO, "Panel Size from BIOS: %dx%d\n",
1141b7e1c893Smrg		       native_mode->PanelXRes, native_mode->PanelYRes);
1142b7e1c893Smrg
1143b7e1c893Smrg	    lvds->PanelPwrDly = RADEON_BIOS16(tmp+44);
1144b7e1c893Smrg	    if (lvds->PanelPwrDly > 2000 || lvds->PanelPwrDly < 0)
1145b7e1c893Smrg		lvds->PanelPwrDly = 2000;
1146209ff23fSmrg
1147209ff23fSmrg	    /* some panels only work well with certain divider combinations.
1148209ff23fSmrg	     */
1149209ff23fSmrg	    info->RefDivider = RADEON_BIOS16(tmp+46);
1150209ff23fSmrg	    info->PostDivider = RADEON_BIOS8(tmp+48);
1151209ff23fSmrg	    info->FeedbackDivider = RADEON_BIOS16(tmp+49);
1152209ff23fSmrg	    if ((info->RefDivider != 0) &&
1153209ff23fSmrg		(info->FeedbackDivider > 3)) {
1154209ff23fSmrg		info->UseBiosDividers = TRUE;
1155209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1156209ff23fSmrg			   "BIOS provided dividers will be used.\n");
1157209ff23fSmrg	    }
1158209ff23fSmrg
1159209ff23fSmrg	    /* We don't use a while loop here just in case we have a corrupted BIOS image.
1160209ff23fSmrg	       The max number of table entries is 23 at present, but may grow in future.
1161209ff23fSmrg	       To ensure it works with future revisions we loop it to 32.
1162209ff23fSmrg	    */
1163209ff23fSmrg	    for (i = 0; i < 32; i++) {
1164209ff23fSmrg		tmp0 = RADEON_BIOS16(tmp+64+i*2);
1165209ff23fSmrg		if (tmp0 == 0) break;
1166b7e1c893Smrg		if ((RADEON_BIOS16(tmp0) == native_mode->PanelXRes) &&
1167b7e1c893Smrg		    (RADEON_BIOS16(tmp0+2) == native_mode->PanelYRes)) {
1168b7e1c893Smrg		    native_mode->HBlank     = (RADEON_BIOS16(tmp0+17) -
1169b7e1c893Smrg					       RADEON_BIOS16(tmp0+19)) * 8;
1170b7e1c893Smrg		    native_mode->HOverPlus  = (RADEON_BIOS16(tmp0+21) -
1171b7e1c893Smrg					       RADEON_BIOS16(tmp0+19) - 1) * 8;
1172b7e1c893Smrg		    native_mode->HSyncWidth = RADEON_BIOS8(tmp0+23) * 8;
1173b7e1c893Smrg		    native_mode->VBlank     = (RADEON_BIOS16(tmp0+24) -
1174b7e1c893Smrg					       RADEON_BIOS16(tmp0+26));
1175b7e1c893Smrg		    native_mode->VOverPlus  = ((RADEON_BIOS16(tmp0+28) & 0x7ff) -
1176b7e1c893Smrg					       RADEON_BIOS16(tmp0+26));
1177b7e1c893Smrg		    native_mode->VSyncWidth = ((RADEON_BIOS16(tmp0+28) & 0xf800) >> 11);
1178b7e1c893Smrg		    native_mode->DotClock   = RADEON_BIOS16(tmp0+9) * 10;
1179b7e1c893Smrg		    native_mode->Flags = 0;
1180209ff23fSmrg		}
1181209ff23fSmrg	    }
1182209ff23fSmrg	}
1183209ff23fSmrg
1184b7e1c893Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1185b7e1c893Smrg		   "LVDS Info:\n"
1186b7e1c893Smrg		   "XRes: %d, YRes: %d, DotClock: %d\n"
1187b7e1c893Smrg		   "HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n"
1188b7e1c893Smrg		   "VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n",
1189b7e1c893Smrg		   native_mode->PanelXRes, native_mode->PanelYRes, native_mode->DotClock,
1190b7e1c893Smrg		   native_mode->HBlank, native_mode->HOverPlus, native_mode->HSyncWidth,
1191b7e1c893Smrg		   native_mode->VBlank, native_mode->VOverPlus, native_mode->VSyncWidth);
1192209ff23fSmrg
1193b7e1c893Smrg	return TRUE;
1194b7e1c893Smrg    }
1195b7e1c893Smrg    return FALSE;
1196209ff23fSmrg}
1197209ff23fSmrg
1198b7e1c893Smrgxf86MonPtr RADEONGetHardCodedEDIDFromBIOS (xf86OutputPtr output)
1199209ff23fSmrg{
1200209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1201b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1202209ff23fSmrg    unsigned long tmp;
1203b7e1c893Smrg    unsigned char edid[256];
1204b7e1c893Smrg    xf86MonPtr mon = NULL;
1205209ff23fSmrg
1206b7e1c893Smrg    if (!info->VBIOS)
1207b7e1c893Smrg	return mon;
1208209ff23fSmrg
1209b7e1c893Smrg    if (!info->IsAtomBios) {
1210b7e1c893Smrg	tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x4c);
1211b7e1c893Smrg	if (tmp) {
1212b7e1c893Smrg	    memcpy(edid, (unsigned char*)(info->VBIOS + tmp), 256);
1213b7e1c893Smrg	    if (edid[1] == 0xff)
1214b7e1c893Smrg		mon = xf86InterpretEDID(output->scrn->scrnIndex, edid);
1215209ff23fSmrg	}
1216209ff23fSmrg    }
1217b7e1c893Smrg
1218b7e1c893Smrg    return mon;
1219209ff23fSmrg}
1220209ff23fSmrg
1221b7e1c893SmrgBool RADEONGetTMDSInfoFromBIOS (ScrnInfoPtr pScrn, radeon_tmds_ptr tmds)
1222209ff23fSmrg{
1223209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1224209ff23fSmrg    uint32_t tmp, maxfreq;
1225209ff23fSmrg    int i, n;
1226209ff23fSmrg
1227209ff23fSmrg    if (!info->VBIOS) return FALSE;
1228209ff23fSmrg
1229209ff23fSmrg    if (info->IsAtomBios) {
1230209ff23fSmrg	if((tmp = RADEON_BIOS16 (info->MasterDataStart + 18))) {
1231209ff23fSmrg
1232209ff23fSmrg	    maxfreq = RADEON_BIOS16(tmp+4);
1233b7e1c893Smrg
1234209ff23fSmrg	    for (i=0; i<4; i++) {
1235b7e1c893Smrg		tmds->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*6+6);
1236209ff23fSmrg		/* This assumes each field in TMDS_PLL has 6 bit as in R300/R420 */
1237b7e1c893Smrg		tmds->tmds_pll[i].value = ((RADEON_BIOS8(tmp+i*6+8) & 0x3f) |
1238209ff23fSmrg					   ((RADEON_BIOS8(tmp+i*6+10) & 0x3f)<<6) |
1239209ff23fSmrg					   ((RADEON_BIOS8(tmp+i*6+9) & 0xf)<<12) |
1240209ff23fSmrg					   ((RADEON_BIOS8(tmp+i*6+11) & 0xf)<<16));
1241b7e1c893Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1242b7e1c893Smrg			   "TMDS PLL from BIOS: %u %x\n",
1243b7e1c893Smrg			   (unsigned)tmds->tmds_pll[i].freq,
1244b7e1c893Smrg			   (unsigned)tmds->tmds_pll[i].value);
1245b7e1c893Smrg
1246b7e1c893Smrg		if (maxfreq == tmds->tmds_pll[i].freq) {
1247b7e1c893Smrg		    tmds->tmds_pll[i].freq = 0xffffffff;
1248209ff23fSmrg		    break;
1249209ff23fSmrg		}
1250209ff23fSmrg	    }
1251209ff23fSmrg	    return TRUE;
1252209ff23fSmrg	}
1253209ff23fSmrg    } else {
1254209ff23fSmrg
1255209ff23fSmrg	tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x34);
1256209ff23fSmrg	if (tmp) {
1257209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1258209ff23fSmrg		       "DFP table revision: %d\n", RADEON_BIOS8(tmp));
1259209ff23fSmrg	    if (RADEON_BIOS8(tmp) == 3) {
1260209ff23fSmrg		n = RADEON_BIOS8(tmp + 5) + 1;
1261209ff23fSmrg		if (n > 4) n = 4;
1262209ff23fSmrg		for (i=0; i<n; i++) {
1263b7e1c893Smrg		    tmds->tmds_pll[i].value = RADEON_BIOS32(tmp+i*10+0x08);
1264b7e1c893Smrg		    tmds->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*10+0x10);
1265209ff23fSmrg		}
1266209ff23fSmrg		return TRUE;
1267209ff23fSmrg	    } else if (RADEON_BIOS8(tmp) == 4) {
1268209ff23fSmrg	        int stride = 0;
1269209ff23fSmrg		n = RADEON_BIOS8(tmp + 5) + 1;
1270209ff23fSmrg		if (n > 4) n = 4;
1271209ff23fSmrg		for (i=0; i<n; i++) {
1272b7e1c893Smrg		    tmds->tmds_pll[i].value = RADEON_BIOS32(tmp+stride+0x08);
1273b7e1c893Smrg		    tmds->tmds_pll[i].freq = RADEON_BIOS16(tmp+stride+0x10);
1274209ff23fSmrg		    if (i == 0) stride += 10;
1275209ff23fSmrg		    else stride += 6;
1276209ff23fSmrg		}
1277209ff23fSmrg		return TRUE;
1278209ff23fSmrg	    }
1279209ff23fSmrg	}
1280209ff23fSmrg    }
1281209ff23fSmrg    return FALSE;
1282209ff23fSmrg}
1283209ff23fSmrg
1284b7e1c893Smrgstatic RADEONI2CBusRec
1285b7e1c893SmrgRADEONLookupI2CBlock(ScrnInfoPtr pScrn, int id)
1286b7e1c893Smrg{
1287b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1288b7e1c893Smrg    int offset, blocks, i;
1289b7e1c893Smrg    RADEONI2CBusRec i2c;
1290b7e1c893Smrg
1291b7e1c893Smrg    memset(&i2c, 0, sizeof(RADEONI2CBusRec));
1292b7e1c893Smrg    i2c.valid = FALSE;
1293b7e1c893Smrg
1294b7e1c893Smrg    offset = RADEON_BIOS16(info->ROMHeaderStart + 0x70);
1295b7e1c893Smrg    if (offset) {
1296b7e1c893Smrg	blocks = RADEON_BIOS8(offset + 2);
1297b7e1c893Smrg	for (i = 0; i < blocks; i++) {
1298b7e1c893Smrg	    int i2c_id = RADEON_BIOS8(offset + 3 + (i * 5) + 0);
1299b7e1c893Smrg	    if (id == i2c_id) {
1300b7e1c893Smrg		int clock_shift = RADEON_BIOS8(offset + 3 + (i * 5) + 3);
1301b7e1c893Smrg		int data_shift = RADEON_BIOS8(offset + 3 + (i * 5) + 4);
1302b7e1c893Smrg
1303b7e1c893Smrg		i2c.mask_clk_mask = (1 << clock_shift);
1304b7e1c893Smrg		i2c.mask_data_mask = (1 << data_shift);
1305b7e1c893Smrg		i2c.a_clk_mask = (1 << clock_shift);
1306b7e1c893Smrg		i2c.a_data_mask = (1 << data_shift);
1307b7e1c893Smrg		i2c.put_clk_mask = (1 << clock_shift);
1308b7e1c893Smrg		i2c.put_data_mask = (1 << data_shift);
1309b7e1c893Smrg		i2c.get_clk_mask = (1 << clock_shift);
1310b7e1c893Smrg		i2c.get_data_mask = (1 << data_shift);
1311ad43ddacSmrg		i2c.mask_clk_reg = RADEON_GPIOPAD_MASK;
1312ad43ddacSmrg		i2c.mask_data_reg = RADEON_GPIOPAD_MASK;
1313ad43ddacSmrg		i2c.a_clk_reg = RADEON_GPIOPAD_A;
1314ad43ddacSmrg		i2c.a_data_reg = RADEON_GPIOPAD_A;
1315ad43ddacSmrg		i2c.put_clk_reg = RADEON_GPIOPAD_EN;
1316ad43ddacSmrg		i2c.put_data_reg = RADEON_GPIOPAD_EN;
1317ad43ddacSmrg		i2c.get_clk_reg = RADEON_LCD_GPIO_Y_REG;
1318ad43ddacSmrg		i2c.get_data_reg = RADEON_LCD_GPIO_Y_REG;
1319b7e1c893Smrg		i2c.valid = TRUE;
1320b7e1c893Smrg		break;
1321b7e1c893Smrg	    }
1322b7e1c893Smrg	}
1323b7e1c893Smrg    }
1324b7e1c893Smrg    return i2c;
1325b7e1c893Smrg}
1326b7e1c893Smrg
1327b7e1c893SmrgBool RADEONGetExtTMDSInfoFromBIOS (ScrnInfoPtr pScrn, radeon_dvo_ptr dvo)
1328209ff23fSmrg{
1329209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1330209ff23fSmrg    int offset, table_start, max_freq, gpio_reg, flags;
1331209ff23fSmrg
1332b7e1c893Smrg    if (!info->VBIOS)
1333b7e1c893Smrg	return FALSE;
1334209ff23fSmrg
1335b7e1c893Smrg    if (info->IsAtomBios)
1336209ff23fSmrg	return FALSE;
1337b7e1c893Smrg    else if (info->IsIGP) {
1338b7e1c893Smrg	/* RS4xx TMDS stuff is in the mobile table */
1339b7e1c893Smrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x42);
1340b7e1c893Smrg	if (offset) {
1341b7e1c893Smrg	    int rev = RADEON_BIOS8(offset);
1342b7e1c893Smrg	    if (rev >= 6) {
1343b7e1c893Smrg		offset = RADEON_BIOS16(offset + 0x17);
1344b7e1c893Smrg		if (offset) {
1345b7e1c893Smrg		    offset = RADEON_BIOS16(offset + 2);
1346b7e1c893Smrg		    rev = RADEON_BIOS8(offset);
1347b7e1c893Smrg		    if (offset && (rev > 1)) {
1348b7e1c893Smrg			int blocks = RADEON_BIOS8(offset + 3);
1349b7e1c893Smrg			int index = offset + 4;
1350b7e1c893Smrg			dvo->dvo_i2c.valid = FALSE;
1351b7e1c893Smrg			while (blocks > 0) {
1352b7e1c893Smrg			    int id = RADEON_BIOS16(index);
1353b7e1c893Smrg			    index += 2;
1354b7e1c893Smrg			    switch (id >> 13) {
1355b7e1c893Smrg			    case 0:
1356b7e1c893Smrg				index += 6;
1357b7e1c893Smrg				break;
1358b7e1c893Smrg			    case 2:
1359b7e1c893Smrg				index += 10;
1360b7e1c893Smrg				break;
1361b7e1c893Smrg			    case 3:
1362b7e1c893Smrg				index += 2;
1363b7e1c893Smrg				break;
1364b7e1c893Smrg			    case 4:
1365b7e1c893Smrg				index += 2;
1366b7e1c893Smrg				break;
1367b7e1c893Smrg			    case 6:
1368b7e1c893Smrg				dvo->dvo_i2c_slave_addr =
1369b7e1c893Smrg				    RADEON_BIOS16(index) & 0xff;
1370b7e1c893Smrg				index += 2;
1371b7e1c893Smrg				dvo->dvo_i2c =
1372b7e1c893Smrg				    RADEONLookupI2CBlock(pScrn, RADEON_BIOS8(index));
1373b7e1c893Smrg				return TRUE;
1374b7e1c893Smrg			    default:
1375b7e1c893Smrg				break;
1376b7e1c893Smrg			    }
1377b7e1c893Smrg			    blocks--;
1378b7e1c893Smrg			}
1379b7e1c893Smrg		    }
1380b7e1c893Smrg		}
1381b7e1c893Smrg	    }
1382ad43ddacSmrg	} else {
1383ad43ddacSmrg	    dvo->dvo_i2c_slave_addr = 0x70;
1384ad43ddacSmrg	    dvo->dvo_i2c = RADEONLookupI2CBlock(pScrn, 136);
1385ad43ddacSmrg	    info->ext_tmds_chip = RADEON_SIL_164;
1386b7e1c893Smrg	}
1387209ff23fSmrg    } else {
1388209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x58);
1389209ff23fSmrg	if (offset) {
1390209ff23fSmrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1391209ff23fSmrg			"External TMDS Table revision: %d\n",
1392209ff23fSmrg			RADEON_BIOS8(offset));
1393209ff23fSmrg	    table_start = offset+4;
1394209ff23fSmrg	    max_freq = RADEON_BIOS16(table_start);
1395b7e1c893Smrg	    dvo->dvo_i2c_slave_addr = RADEON_BIOS8(table_start+2);
1396b7e1c893Smrg	    dvo->dvo_i2c.valid = FALSE;
1397209ff23fSmrg	    gpio_reg = RADEON_BIOS8(table_start+3);
1398209ff23fSmrg	    if (gpio_reg == 1)
1399b7e1c893Smrg		dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID);
1400209ff23fSmrg	    else if (gpio_reg == 2)
1401b7e1c893Smrg		dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
1402209ff23fSmrg	    else if (gpio_reg == 3)
1403b7e1c893Smrg		dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
1404ad43ddacSmrg	    else if (gpio_reg == 4) {
1405ad43ddacSmrg		if (IS_R300_VARIANT)
1406ad43ddacSmrg		    dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID);
1407ad43ddacSmrg		else
1408ad43ddacSmrg		    dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
1409ad43ddacSmrg	    } else if (gpio_reg == 5) {
1410209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1411209ff23fSmrg			   "unsupported MM gpio_reg\n");
1412b7e1c893Smrg		return FALSE;
1413b7e1c893Smrg	    } else {
1414209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1415209ff23fSmrg			   "Unknown gpio reg: %d\n", gpio_reg);
1416209ff23fSmrg		return FALSE;
1417209ff23fSmrg	    }
1418209ff23fSmrg	    flags = RADEON_BIOS8(table_start+5);
1419b7e1c893Smrg	    dvo->dvo_duallink = flags & 0x01;
1420b7e1c893Smrg	    if (dvo->dvo_duallink) {
1421209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1422209ff23fSmrg			   "Duallink TMDS detected\n");
1423209ff23fSmrg	    }
1424209ff23fSmrg	    return TRUE;
1425209ff23fSmrg	}
1426209ff23fSmrg    }
1427209ff23fSmrg
1428209ff23fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1429209ff23fSmrg	       "No External TMDS Table found\n");
1430209ff23fSmrg
1431209ff23fSmrg    return FALSE;
1432209ff23fSmrg}
1433209ff23fSmrg
1434209ff23fSmrgBool RADEONInitExtTMDSInfoFromBIOS (xf86OutputPtr output)
1435209ff23fSmrg{
1436209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1437209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1438209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1439b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1440b7e1c893Smrg    radeon_dvo_ptr dvo = NULL;
1441209ff23fSmrg    int offset, index, id;
1442b7e1c893Smrg    uint32_t val, reg, and_mask, or_mask;
1443209ff23fSmrg
1444b7e1c893Smrg    if (radeon_encoder == NULL)
1445b7e1c893Smrg	return FALSE;
1446209ff23fSmrg
1447b7e1c893Smrg    dvo = (radeon_dvo_ptr)radeon_encoder->dev_priv;
1448b7e1c893Smrg
1449b7e1c893Smrg    if (dvo == NULL)
1450b7e1c893Smrg	return FALSE;
1451b7e1c893Smrg
1452b7e1c893Smrg    if (!info->VBIOS)
1453b7e1c893Smrg	return FALSE;
1454b7e1c893Smrg
1455b7e1c893Smrg    if (info->IsAtomBios)
1456209ff23fSmrg	return FALSE;
1457b7e1c893Smrg    else if (info->IsIGP) {
1458b7e1c893Smrg	/* RS4xx TMDS stuff is in the mobile table */
1459b7e1c893Smrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x42);
1460b7e1c893Smrg	if (offset) {
1461b7e1c893Smrg	    int rev = RADEON_BIOS8(offset);
1462b7e1c893Smrg	    if (rev >= 6) {
1463b7e1c893Smrg		offset = RADEON_BIOS16(offset + 0x17);
1464b7e1c893Smrg		if (offset) {
1465b7e1c893Smrg		    offset = RADEON_BIOS16(offset + 2);
1466b7e1c893Smrg		    rev = RADEON_BIOS8(offset);
1467b7e1c893Smrg		    if (offset && (rev > 1)) {
1468b7e1c893Smrg			int blocks = RADEON_BIOS8(offset + 3);
1469b7e1c893Smrg			index = offset + 4;
1470b7e1c893Smrg			while (blocks > 0) {
1471b7e1c893Smrg			    id = RADEON_BIOS16(index);
1472b7e1c893Smrg			    index += 2;
1473b7e1c893Smrg			    switch (id >> 13) {
1474b7e1c893Smrg			    case 0:
1475b7e1c893Smrg				reg = (id & 0x1fff) * 4;
1476b7e1c893Smrg				val = RADEON_BIOS32(index);
1477b7e1c893Smrg				index += 4;
1478b7e1c893Smrg				ErrorF("MMIO: 0x%x 0x%x\n",
1479b7e1c893Smrg				       (unsigned)reg, (unsigned)val);
1480b7e1c893Smrg				OUTREG(reg, val);
1481b7e1c893Smrg				break;
1482b7e1c893Smrg			    case 2:
1483b7e1c893Smrg				reg = (id & 0x1fff) * 4;
1484b7e1c893Smrg				and_mask = RADEON_BIOS32(index);
1485b7e1c893Smrg				index += 4;
1486b7e1c893Smrg				or_mask = RADEON_BIOS32(index);
1487b7e1c893Smrg				index += 4;
1488b7e1c893Smrg				ErrorF("MMIO mask: 0x%x 0x%x 0x%x\n",
1489b7e1c893Smrg				       (unsigned)reg, (unsigned)and_mask, (unsigned)or_mask);
1490b7e1c893Smrg				val = INREG(reg);
1491b7e1c893Smrg				val = (val & and_mask) | or_mask;
1492b7e1c893Smrg				OUTREG(reg, val);
1493b7e1c893Smrg				break;
1494b7e1c893Smrg			    case 3:
1495b7e1c893Smrg				val = RADEON_BIOS16(index);
1496b7e1c893Smrg				index += 2;
1497b7e1c893Smrg				ErrorF("delay: %u\n", (unsigned)val);
1498b7e1c893Smrg				usleep(val);
1499b7e1c893Smrg				break;
1500b7e1c893Smrg			    case 4:
1501b7e1c893Smrg				val = RADEON_BIOS16(index);
1502b7e1c893Smrg				index += 2;
1503b7e1c893Smrg				ErrorF("delay: %u\n", (unsigned)val * 1000);
1504b7e1c893Smrg				usleep(val * 1000);
1505b7e1c893Smrg				break;
1506b7e1c893Smrg			    case 6:
1507b7e1c893Smrg				index++;
1508b7e1c893Smrg				reg = RADEON_BIOS8(index);
1509b7e1c893Smrg				index++;
1510b7e1c893Smrg				val = RADEON_BIOS8(index);
1511b7e1c893Smrg				index++;
1512b7e1c893Smrg				ErrorF("i2c write: 0x%x, 0x%x\n", (unsigned)reg,
1513b7e1c893Smrg				       (unsigned)val);
1514b7e1c893Smrg				RADEONDVOWriteByte(dvo->DVOChip, reg, val);
1515b7e1c893Smrg				break;
1516b7e1c893Smrg			    default:
1517b7e1c893Smrg				ErrorF("unknown id %d\n", id>>13);
1518b7e1c893Smrg				return FALSE;
1519b7e1c893Smrg			    }
1520b7e1c893Smrg			    blocks--;
1521b7e1c893Smrg			}
1522b7e1c893Smrg			return TRUE;
1523b7e1c893Smrg		    }
1524b7e1c893Smrg		}
1525b7e1c893Smrg	    }
1526b7e1c893Smrg	}
1527209ff23fSmrg    } else {
1528209ff23fSmrg	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x58);
1529209ff23fSmrg	if (offset) {
1530209ff23fSmrg	    index = offset+10;
1531209ff23fSmrg	    id = RADEON_BIOS16(index);
1532209ff23fSmrg	    while (id != 0xffff) {
1533209ff23fSmrg		index += 2;
1534209ff23fSmrg		switch(id >> 13) {
1535209ff23fSmrg		case 0:
1536b7e1c893Smrg		    reg = (id & 0x1fff) * 4;
1537209ff23fSmrg		    val = RADEON_BIOS32(index);
1538209ff23fSmrg		    index += 4;
1539b7e1c893Smrg		    ErrorF("MMIO: 0x%x 0x%x\n",
1540209ff23fSmrg			   (unsigned)reg, (unsigned)val);
1541b7e1c893Smrg		    OUTREG(reg, val);
1542209ff23fSmrg		    break;
1543209ff23fSmrg		case 2:
1544b7e1c893Smrg		    reg = (id & 0x1fff) * 4;
1545b7e1c893Smrg		    and_mask = RADEON_BIOS32(index);
1546209ff23fSmrg		    index += 4;
1547b7e1c893Smrg		    or_mask = RADEON_BIOS32(index);
1548209ff23fSmrg		    index += 4;
1549209ff23fSmrg		    val = INREG(reg);
1550b7e1c893Smrg		    val = (val & and_mask) | or_mask;
1551b7e1c893Smrg		    ErrorF("MMIO mask: 0x%x 0x%x 0x%x\n",
1552b7e1c893Smrg			   (unsigned)reg, (unsigned)and_mask, (unsigned)or_mask);
1553b7e1c893Smrg		    OUTREG(reg, val);
1554209ff23fSmrg		    break;
1555209ff23fSmrg		case 4:
1556209ff23fSmrg		    val = RADEON_BIOS16(index);
1557209ff23fSmrg		    index += 2;
1558209ff23fSmrg		    ErrorF("delay: %u\n", (unsigned)val);
1559209ff23fSmrg		    usleep(val);
1560209ff23fSmrg		    break;
1561209ff23fSmrg		case 5:
1562209ff23fSmrg		    reg = id & 0x1fff;
1563b7e1c893Smrg		    and_mask = RADEON_BIOS32(index);
1564209ff23fSmrg		    index += 4;
1565b7e1c893Smrg		    or_mask = RADEON_BIOS32(index);
1566209ff23fSmrg		    index += 4;
1567b7e1c893Smrg		    ErrorF("PLL mask: 0x%x 0x%x 0x%x\n",
1568b7e1c893Smrg			   (unsigned)reg, (unsigned)and_mask, (unsigned)or_mask);
1569b7e1c893Smrg		    val = INPLL(pScrn, reg);
1570b7e1c893Smrg		    val = (val & and_mask) | or_mask;
1571b7e1c893Smrg		    OUTPLL(pScrn, reg, val);
1572209ff23fSmrg		    break;
1573209ff23fSmrg		case 6:
1574209ff23fSmrg		    reg = id & 0x1fff;
1575209ff23fSmrg		    val = RADEON_BIOS8(index);
1576209ff23fSmrg		    index += 1;
1577209ff23fSmrg		    ErrorF("i2c write: 0x%x, 0x%x\n", (unsigned)reg,
1578209ff23fSmrg			   (unsigned)val);
1579b7e1c893Smrg		    RADEONDVOWriteByte(dvo->DVOChip, reg, val);
1580209ff23fSmrg		    break;
1581209ff23fSmrg		default:
1582209ff23fSmrg		    ErrorF("unknown id %d\n", id>>13);
1583209ff23fSmrg		    return FALSE;
1584209ff23fSmrg		};
1585209ff23fSmrg		id = RADEON_BIOS16(index);
1586209ff23fSmrg	    }
1587209ff23fSmrg	    return TRUE;
1588209ff23fSmrg	}
1589209ff23fSmrg    }
1590209ff23fSmrg
1591209ff23fSmrg    return FALSE;
1592209ff23fSmrg}
1593209ff23fSmrg
1594209ff23fSmrg/* support for init from bios tables
1595209ff23fSmrg *
1596209ff23fSmrg * Based heavily on the netbsd radeonfb driver
1597209ff23fSmrg * Written by Garrett D'Amore
1598209ff23fSmrg * Copyright (c) 2006 Itronix Inc.
1599209ff23fSmrg *
1600209ff23fSmrg */
1601209ff23fSmrg
1602209ff23fSmrg/* bios table defines */
1603209ff23fSmrg
1604209ff23fSmrg#define RADEON_TABLE_ENTRY_FLAG_MASK    0xe000
1605209ff23fSmrg#define RADEON_TABLE_ENTRY_INDEX_MASK   0x1fff
1606209ff23fSmrg#define RADEON_TABLE_ENTRY_COMMAND_MASK 0x00ff
1607209ff23fSmrg
1608209ff23fSmrg#define RADEON_TABLE_FLAG_WRITE_INDEXED 0x0000
1609209ff23fSmrg#define RADEON_TABLE_FLAG_WRITE_DIRECT  0x2000
1610209ff23fSmrg#define RADEON_TABLE_FLAG_MASK_INDEXED  0x4000
1611209ff23fSmrg#define RADEON_TABLE_FLAG_MASK_DIRECT   0x6000
1612209ff23fSmrg#define RADEON_TABLE_FLAG_DELAY         0x8000
1613209ff23fSmrg#define RADEON_TABLE_FLAG_SCOMMAND      0xa000
1614209ff23fSmrg
1615209ff23fSmrg#define RADEON_TABLE_SCOMMAND_WAIT_MC_BUSY_MASK       0x03
1616209ff23fSmrg#define RADEON_TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE 0x08
1617209ff23fSmrg
1618209ff23fSmrg#define RADEON_PLL_FLAG_MASK      0xc0
1619209ff23fSmrg#define RADEON_PLL_INDEX_MASK     0x3f
1620209ff23fSmrg
1621209ff23fSmrg#define RADEON_PLL_FLAG_WRITE     0x00
1622209ff23fSmrg#define RADEON_PLL_FLAG_MASK_BYTE 0x40
1623209ff23fSmrg#define RADEON_PLL_FLAG_WAIT      0x80
1624209ff23fSmrg
1625209ff23fSmrg#define RADEON_PLL_WAIT_150MKS                    1
1626209ff23fSmrg#define RADEON_PLL_WAIT_5MS                       2
1627209ff23fSmrg#define RADEON_PLL_WAIT_MC_BUSY_MASK              3
1628209ff23fSmrg#define RADEON_PLL_WAIT_DLL_READY_MASK            4
1629209ff23fSmrg#define RADEON_PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24 5
1630209ff23fSmrg
1631209ff23fSmrgstatic uint16_t
1632209ff23fSmrgRADEONValidateBIOSOffset(ScrnInfoPtr pScrn, uint16_t offset)
1633209ff23fSmrg{
1634209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1635209ff23fSmrg    uint8_t revision = RADEON_BIOS8(offset - 1);
1636209ff23fSmrg
1637209ff23fSmrg    if (revision > 0x10) {
1638209ff23fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1639209ff23fSmrg                   "Bad revision %d for BIOS table\n", revision);
1640209ff23fSmrg        return 0;
1641209ff23fSmrg    }
1642209ff23fSmrg
1643209ff23fSmrg    if (offset < 0x60) {
1644209ff23fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1645209ff23fSmrg                   "Bad offset 0x%x for BIOS Table\n", offset);
1646209ff23fSmrg        return 0;
1647209ff23fSmrg    }
1648209ff23fSmrg
1649209ff23fSmrg    return offset;
1650209ff23fSmrg}
1651209ff23fSmrg
1652209ff23fSmrgBool
1653209ff23fSmrgRADEONGetBIOSInitTableOffsets(ScrnInfoPtr pScrn)
1654209ff23fSmrg{
1655209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1656209ff23fSmrg    uint8_t val;
1657209ff23fSmrg
1658209ff23fSmrg    if (!info->VBIOS) {
1659209ff23fSmrg	return FALSE;
1660209ff23fSmrg    } else {
1661209ff23fSmrg	if (info->IsAtomBios) {
1662209ff23fSmrg	    return FALSE;
1663209ff23fSmrg	} else {
1664209ff23fSmrg	    info->BiosTable.revision = RADEON_BIOS8(info->ROMHeaderStart + 4);
1665209ff23fSmrg	    info->BiosTable.rr1_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x0c);
1666209ff23fSmrg	    if (info->BiosTable.rr1_offset) {
1667209ff23fSmrg		info->BiosTable.rr1_offset =
1668209ff23fSmrg		    RADEONValidateBIOSOffset(pScrn, info->BiosTable.rr1_offset);
1669209ff23fSmrg	    }
1670209ff23fSmrg	    if (info->BiosTable.revision > 0x09)
1671209ff23fSmrg		return TRUE;
1672209ff23fSmrg	    info->BiosTable.rr2_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x4e);
1673209ff23fSmrg	    if (info->BiosTable.rr2_offset) {
1674209ff23fSmrg		info->BiosTable.rr2_offset =
1675209ff23fSmrg		    RADEONValidateBIOSOffset(pScrn, info->BiosTable.rr2_offset);
1676209ff23fSmrg	    }
1677209ff23fSmrg	    info->BiosTable.dyn_clk_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x52);
1678209ff23fSmrg	    if (info->BiosTable.dyn_clk_offset) {
1679209ff23fSmrg		info->BiosTable.dyn_clk_offset =
1680209ff23fSmrg		    RADEONValidateBIOSOffset(pScrn, info->BiosTable.dyn_clk_offset);
1681209ff23fSmrg	    }
1682209ff23fSmrg	    info->BiosTable.pll_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x46);
1683209ff23fSmrg	    if (info->BiosTable.pll_offset) {
1684209ff23fSmrg		info->BiosTable.pll_offset =
1685209ff23fSmrg		    RADEONValidateBIOSOffset(pScrn, info->BiosTable.pll_offset);
1686209ff23fSmrg	    }
1687209ff23fSmrg	    info->BiosTable.mem_config_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x48);
1688209ff23fSmrg	    if (info->BiosTable.mem_config_offset) {
1689209ff23fSmrg		info->BiosTable.mem_config_offset =
1690209ff23fSmrg		    RADEONValidateBIOSOffset(pScrn, info->BiosTable.mem_config_offset);
1691209ff23fSmrg	    }
1692209ff23fSmrg	    if (info->BiosTable.mem_config_offset) {
1693209ff23fSmrg		info->BiosTable.mem_reset_offset = info->BiosTable.mem_config_offset;
1694209ff23fSmrg		if (info->BiosTable.mem_reset_offset) {
1695209ff23fSmrg		    while (RADEON_BIOS8(info->BiosTable.mem_reset_offset))
1696209ff23fSmrg			info->BiosTable.mem_reset_offset++;
1697209ff23fSmrg		    info->BiosTable.mem_reset_offset++;
1698209ff23fSmrg		    info->BiosTable.mem_reset_offset += 2;
1699209ff23fSmrg		}
1700209ff23fSmrg	    }
1701209ff23fSmrg	    if (info->BiosTable.mem_config_offset) {
1702209ff23fSmrg		info->BiosTable.short_mem_offset = info->BiosTable.mem_config_offset;
1703209ff23fSmrg		if ((info->BiosTable.short_mem_offset != 0) &&
1704209ff23fSmrg		    (RADEON_BIOS8(info->BiosTable.short_mem_offset - 2) <= 64))
1705209ff23fSmrg		    info->BiosTable.short_mem_offset +=
1706209ff23fSmrg			RADEON_BIOS8(info->BiosTable.short_mem_offset - 3);
1707209ff23fSmrg	    }
1708209ff23fSmrg	    if (info->BiosTable.rr2_offset) {
1709209ff23fSmrg		info->BiosTable.rr3_offset = info->BiosTable.rr2_offset;
1710209ff23fSmrg		if (info->BiosTable.rr3_offset) {
1711209ff23fSmrg		    while ((val = RADEON_BIOS8(info->BiosTable.rr3_offset + 1)) != 0) {
1712209ff23fSmrg			if (val & 0x40)
1713209ff23fSmrg			    info->BiosTable.rr3_offset += 10;
1714209ff23fSmrg			else if (val & 0x80)
1715209ff23fSmrg			    info->BiosTable.rr3_offset += 4;
1716209ff23fSmrg			else
1717209ff23fSmrg			    info->BiosTable.rr3_offset += 6;
1718209ff23fSmrg		    }
1719209ff23fSmrg		    info->BiosTable.rr3_offset += 2;
1720209ff23fSmrg		}
1721209ff23fSmrg	    }
1722209ff23fSmrg
1723209ff23fSmrg	    if (info->BiosTable.rr3_offset) {
1724209ff23fSmrg		info->BiosTable.rr4_offset = info->BiosTable.rr3_offset;
1725209ff23fSmrg		if (info->BiosTable.rr4_offset) {
1726209ff23fSmrg		    while ((val = RADEON_BIOS8(info->BiosTable.rr4_offset + 1)) != 0) {
1727209ff23fSmrg			if (val & 0x40)
1728209ff23fSmrg			    info->BiosTable.rr4_offset += 10;
1729209ff23fSmrg			else if (val & 0x80)
1730209ff23fSmrg			    info->BiosTable.rr4_offset += 4;
1731209ff23fSmrg			else
1732209ff23fSmrg			    info->BiosTable.rr4_offset += 6;
1733209ff23fSmrg		    }
1734209ff23fSmrg		    info->BiosTable.rr4_offset += 2;
1735209ff23fSmrg		}
1736209ff23fSmrg	    }
1737209ff23fSmrg
1738209ff23fSmrg	    if (info->BiosTable.rr3_offset + 1 == info->BiosTable.pll_offset) {
1739209ff23fSmrg		info->BiosTable.rr3_offset = 0;
1740209ff23fSmrg		info->BiosTable.rr4_offset = 0;
1741209ff23fSmrg	    }
1742209ff23fSmrg
1743209ff23fSmrg	    return TRUE;
1744209ff23fSmrg
1745209ff23fSmrg	}
1746209ff23fSmrg    }
1747209ff23fSmrg}
1748209ff23fSmrg
1749209ff23fSmrgstatic void
1750209ff23fSmrgRADEONRestoreBIOSRegBlock(ScrnInfoPtr pScrn, uint16_t table_offset)
1751209ff23fSmrg{
1752209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1753209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1754209ff23fSmrg    uint16_t offset = table_offset;
1755209ff23fSmrg    uint16_t value, flag, index, count;
1756209ff23fSmrg    uint32_t andmask, ormask, val, channel_complete_mask;
1757209ff23fSmrg    uint8_t  command;
1758209ff23fSmrg
1759209ff23fSmrg    if (offset == 0)
1760209ff23fSmrg	return;
1761209ff23fSmrg
1762209ff23fSmrg    while ((value = RADEON_BIOS16(offset)) != 0) {
1763209ff23fSmrg	flag = value & RADEON_TABLE_ENTRY_FLAG_MASK;
1764209ff23fSmrg	index = value & RADEON_TABLE_ENTRY_INDEX_MASK;
1765209ff23fSmrg	command = value & RADEON_TABLE_ENTRY_COMMAND_MASK;
1766209ff23fSmrg
1767209ff23fSmrg	offset += 2;
1768209ff23fSmrg
1769209ff23fSmrg	switch (flag) {
1770209ff23fSmrg	case RADEON_TABLE_FLAG_WRITE_INDEXED:
1771209ff23fSmrg	    val = RADEON_BIOS32(offset);
1772209ff23fSmrg	    ErrorF("WRITE INDEXED: 0x%x 0x%x\n",
1773209ff23fSmrg		   index, (unsigned)val);
1774209ff23fSmrg	    OUTREG(RADEON_MM_INDEX, index);
1775209ff23fSmrg	    OUTREG(RADEON_MM_DATA, val);
1776209ff23fSmrg	    offset += 4;
1777209ff23fSmrg	    break;
1778209ff23fSmrg
1779209ff23fSmrg	case RADEON_TABLE_FLAG_WRITE_DIRECT:
1780209ff23fSmrg	    val = RADEON_BIOS32(offset);
1781209ff23fSmrg	    ErrorF("WRITE DIRECT: 0x%x 0x%x\n", index, (unsigned)val);
1782209ff23fSmrg	    OUTREG(index, val);
1783209ff23fSmrg	    offset += 4;
1784209ff23fSmrg	    break;
1785209ff23fSmrg
1786209ff23fSmrg	case RADEON_TABLE_FLAG_MASK_INDEXED:
1787209ff23fSmrg	    andmask = RADEON_BIOS32(offset);
1788209ff23fSmrg	    offset += 4;
1789209ff23fSmrg	    ormask = RADEON_BIOS32(offset);
1790209ff23fSmrg	    offset += 4;
1791209ff23fSmrg	    ErrorF("MASK INDEXED: 0x%x 0x%x 0x%x\n",
1792209ff23fSmrg		   index, (unsigned)andmask, (unsigned)ormask);
1793209ff23fSmrg	    OUTREG(RADEON_MM_INDEX, index);
1794209ff23fSmrg	    val = INREG(RADEON_MM_DATA);
1795209ff23fSmrg	    val = (val & andmask) | ormask;
1796209ff23fSmrg	    OUTREG(RADEON_MM_DATA, val);
1797209ff23fSmrg	    break;
1798209ff23fSmrg
1799209ff23fSmrg	case RADEON_TABLE_FLAG_MASK_DIRECT:
1800209ff23fSmrg	    andmask = RADEON_BIOS32(offset);
1801209ff23fSmrg	    offset += 4;
1802209ff23fSmrg	    ormask = RADEON_BIOS32(offset);
1803209ff23fSmrg	    offset += 4;
1804209ff23fSmrg	    ErrorF("MASK DIRECT: 0x%x 0x%x 0x%x\n",
1805209ff23fSmrg		   index, (unsigned)andmask, (unsigned)ormask);
1806209ff23fSmrg	    val = INREG(index);
1807209ff23fSmrg	    val = (val & andmask) | ormask;
1808209ff23fSmrg	    OUTREG(index, val);
1809209ff23fSmrg	    break;
1810209ff23fSmrg
1811209ff23fSmrg	case RADEON_TABLE_FLAG_DELAY:
1812209ff23fSmrg	    count = RADEON_BIOS16(offset);
1813209ff23fSmrg	    ErrorF("delay: %d\n", count);
1814209ff23fSmrg	    usleep(count);
1815209ff23fSmrg	    offset += 2;
1816209ff23fSmrg	    break;
1817209ff23fSmrg
1818209ff23fSmrg	case RADEON_TABLE_FLAG_SCOMMAND:
1819209ff23fSmrg	    ErrorF("SCOMMAND 0x%x\n", command);
1820209ff23fSmrg	    switch (command) {
1821209ff23fSmrg	    case RADEON_TABLE_SCOMMAND_WAIT_MC_BUSY_MASK:
1822209ff23fSmrg		count = RADEON_BIOS16(offset);
1823209ff23fSmrg		ErrorF("SCOMMAND_WAIT_MC_BUSY_MASK %d\n", count);
1824209ff23fSmrg		while (count--) {
1825209ff23fSmrg		    if (!(INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) &
1826209ff23fSmrg			  RADEON_MC_BUSY))
1827209ff23fSmrg			break;
1828209ff23fSmrg		}
1829209ff23fSmrg		break;
1830209ff23fSmrg
1831209ff23fSmrg	    case RADEON_TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE:
1832209ff23fSmrg		count = RADEON_BIOS16(offset);
1833209ff23fSmrg		ErrorF("SCOMMAND_WAIT_MEM_PWRUP_COMPLETE %d\n", count);
1834209ff23fSmrg		/* may need to take into account how many memory channels
1835209ff23fSmrg		 * each card has
1836209ff23fSmrg		 */
1837209ff23fSmrg		if (IS_R300_VARIANT)
1838209ff23fSmrg		    channel_complete_mask = R300_MEM_PWRUP_COMPLETE;
1839209ff23fSmrg		else
1840209ff23fSmrg		    channel_complete_mask = RADEON_MEM_PWRUP_COMPLETE;
1841209ff23fSmrg		while (count--) {
1842209ff23fSmrg		    /* XXX: may need indexed access */
1843209ff23fSmrg		    if ((INREG(RADEON_MEM_STR_CNTL) &
1844209ff23fSmrg			 channel_complete_mask) ==
1845209ff23fSmrg		        channel_complete_mask)
1846209ff23fSmrg			break;
1847209ff23fSmrg		}
1848209ff23fSmrg		break;
1849209ff23fSmrg
1850209ff23fSmrg	    }
1851209ff23fSmrg	    offset += 2;
1852209ff23fSmrg	    break;
1853209ff23fSmrg	}
1854209ff23fSmrg    }
1855209ff23fSmrg}
1856209ff23fSmrg
1857209ff23fSmrgstatic void
1858209ff23fSmrgRADEONRestoreBIOSMemBlock(ScrnInfoPtr pScrn, uint16_t table_offset)
1859209ff23fSmrg{
1860209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1861209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1862209ff23fSmrg    uint16_t offset = table_offset;
1863209ff23fSmrg    uint16_t count;
1864209ff23fSmrg    uint32_t ormask, val, channel_complete_mask;
1865209ff23fSmrg    uint8_t  index;
1866209ff23fSmrg
1867209ff23fSmrg    if (offset == 0)
1868209ff23fSmrg	return;
1869209ff23fSmrg
1870209ff23fSmrg    while ((index = RADEON_BIOS8(offset)) != 0xff) {
1871209ff23fSmrg	offset++;
1872209ff23fSmrg	if (index == 0x0f) {
1873209ff23fSmrg	    count = 20000;
1874209ff23fSmrg	    ErrorF("MEM_WAIT_MEM_PWRUP_COMPLETE %d\n", count);
1875209ff23fSmrg	    /* may need to take into account how many memory channels
1876209ff23fSmrg	     * each card has
1877209ff23fSmrg	     */
1878209ff23fSmrg	    if (IS_R300_VARIANT)
1879209ff23fSmrg		channel_complete_mask = R300_MEM_PWRUP_COMPLETE;
1880209ff23fSmrg	    else
1881209ff23fSmrg		channel_complete_mask = RADEON_MEM_PWRUP_COMPLETE;
1882209ff23fSmrg	    while (count--) {
1883209ff23fSmrg		/* XXX: may need indexed access */
1884209ff23fSmrg		if ((INREG(RADEON_MEM_STR_CNTL) &
1885209ff23fSmrg		     channel_complete_mask) ==
1886209ff23fSmrg		    channel_complete_mask)
1887209ff23fSmrg		    break;
1888209ff23fSmrg	    }
1889209ff23fSmrg	} else {
1890209ff23fSmrg	    ormask = RADEON_BIOS16(offset);
1891209ff23fSmrg	    offset += 2;
1892209ff23fSmrg
1893209ff23fSmrg	    ErrorF("INDEX RADEON_MEM_SDRAM_MODE_REG %x %x\n",
1894209ff23fSmrg		   RADEON_SDRAM_MODE_MASK, (unsigned)ormask);
1895209ff23fSmrg
1896209ff23fSmrg	    /* can this use direct access? */
1897209ff23fSmrg	    OUTREG(RADEON_MM_INDEX, RADEON_MEM_SDRAM_MODE_REG);
1898209ff23fSmrg	    val = INREG(RADEON_MM_DATA);
1899209ff23fSmrg	    val = (val & RADEON_SDRAM_MODE_MASK) | ormask;
1900209ff23fSmrg	    OUTREG(RADEON_MM_DATA, val);
1901209ff23fSmrg
1902209ff23fSmrg	    ormask = (uint32_t)index << 24;
1903209ff23fSmrg
1904209ff23fSmrg	    ErrorF("INDEX RADEON_MEM_SDRAM_MODE_REG %x %x\n",
1905209ff23fSmrg		   RADEON_B3MEM_RESET_MASK, (unsigned)ormask);
1906209ff23fSmrg
1907209ff23fSmrg            /* can this use direct access? */
1908209ff23fSmrg            OUTREG(RADEON_MM_INDEX, RADEON_MEM_SDRAM_MODE_REG);
1909209ff23fSmrg            val = INREG(RADEON_MM_DATA);
1910209ff23fSmrg            val = (val & RADEON_B3MEM_RESET_MASK) | ormask;
1911209ff23fSmrg            OUTREG(RADEON_MM_DATA, val);
1912209ff23fSmrg	}
1913209ff23fSmrg    }
1914209ff23fSmrg}
1915209ff23fSmrg
1916209ff23fSmrgstatic void
1917209ff23fSmrgRADEONRestoreBIOSPllBlock(ScrnInfoPtr pScrn, uint16_t table_offset)
1918209ff23fSmrg{
1919209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1920209ff23fSmrg    uint16_t offset = table_offset;
1921209ff23fSmrg    uint8_t  index, shift;
1922209ff23fSmrg    uint32_t andmask, ormask, val, clk_pwrmgt_cntl;
1923209ff23fSmrg    uint16_t count;
1924209ff23fSmrg
1925209ff23fSmrg    if (offset == 0)
1926209ff23fSmrg	return;
1927209ff23fSmrg
1928209ff23fSmrg    while ((index = RADEON_BIOS8(offset)) != 0) {
1929209ff23fSmrg	offset++;
1930209ff23fSmrg
1931209ff23fSmrg	switch (index & RADEON_PLL_FLAG_MASK) {
1932209ff23fSmrg	case RADEON_PLL_FLAG_WAIT:
1933209ff23fSmrg	    switch (index & RADEON_PLL_INDEX_MASK) {
1934209ff23fSmrg	    case RADEON_PLL_WAIT_150MKS:
1935209ff23fSmrg		ErrorF("delay: 150 us\n");
1936209ff23fSmrg		usleep(150);
1937209ff23fSmrg		break;
1938209ff23fSmrg	    case RADEON_PLL_WAIT_5MS:
1939209ff23fSmrg		ErrorF("delay: 5 ms\n");
1940209ff23fSmrg		usleep(5000);
1941209ff23fSmrg		break;
1942209ff23fSmrg
1943209ff23fSmrg	    case RADEON_PLL_WAIT_MC_BUSY_MASK:
1944209ff23fSmrg		count = 1000;
1945209ff23fSmrg		ErrorF("PLL_WAIT_MC_BUSY_MASK %d\n", count);
1946209ff23fSmrg		while (count--) {
1947209ff23fSmrg		    if (!(INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) &
1948209ff23fSmrg			  RADEON_MC_BUSY))
1949209ff23fSmrg			break;
1950209ff23fSmrg		}
1951209ff23fSmrg		break;
1952209ff23fSmrg
1953209ff23fSmrg	    case RADEON_PLL_WAIT_DLL_READY_MASK:
1954209ff23fSmrg		count = 1000;
1955209ff23fSmrg		ErrorF("PLL_WAIT_DLL_READY_MASK %d\n", count);
1956209ff23fSmrg		while (count--) {
1957209ff23fSmrg		    if (INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) &
1958209ff23fSmrg			RADEON_DLL_READY)
1959209ff23fSmrg			break;
1960209ff23fSmrg		}
1961209ff23fSmrg		break;
1962209ff23fSmrg
1963209ff23fSmrg	    case RADEON_PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24:
1964209ff23fSmrg		ErrorF("PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24\n");
1965209ff23fSmrg		clk_pwrmgt_cntl = INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL);
1966209ff23fSmrg		if (clk_pwrmgt_cntl & RADEON_CG_NO1_DEBUG_0) {
1967209ff23fSmrg		    val = INPLL(pScrn, RADEON_MCLK_CNTL);
1968209ff23fSmrg		    /* is this right? */
1969209ff23fSmrg		    val = (val & 0xFFFF0000) | 0x1111; /* seems like we should clear these... */
1970209ff23fSmrg		    OUTPLL(pScrn, RADEON_MCLK_CNTL, val);
1971209ff23fSmrg		    usleep(10000);
1972209ff23fSmrg		    OUTPLL(pScrn, RADEON_CLK_PWRMGT_CNTL,
1973209ff23fSmrg			   clk_pwrmgt_cntl & ~RADEON_CG_NO1_DEBUG_0);
1974209ff23fSmrg		    usleep(10000);
1975209ff23fSmrg		}
1976209ff23fSmrg		break;
1977209ff23fSmrg	    }
1978209ff23fSmrg	    break;
1979209ff23fSmrg
1980209ff23fSmrg	case RADEON_PLL_FLAG_MASK_BYTE:
1981209ff23fSmrg	    shift = RADEON_BIOS8(offset) * 8;
1982209ff23fSmrg	    offset++;
1983209ff23fSmrg
1984209ff23fSmrg	    andmask =
1985209ff23fSmrg		(((uint32_t)RADEON_BIOS8(offset)) << shift) |
1986209ff23fSmrg		~((uint32_t)0xff << shift);
1987209ff23fSmrg	    offset++;
1988209ff23fSmrg
1989209ff23fSmrg	    ormask = ((uint32_t)RADEON_BIOS8(offset)) << shift;
1990209ff23fSmrg	    offset++;
1991209ff23fSmrg
1992209ff23fSmrg	    ErrorF("PLL_MASK_BYTE 0x%x 0x%x 0x%x 0x%x\n",
1993209ff23fSmrg		   index, shift, (unsigned)andmask, (unsigned)ormask);
1994209ff23fSmrg	    val = INPLL(pScrn, index);
1995209ff23fSmrg	    val = (val & andmask) | ormask;
1996209ff23fSmrg	    OUTPLL(pScrn, index, val);
1997209ff23fSmrg	    break;
1998209ff23fSmrg
1999209ff23fSmrg	case RADEON_PLL_FLAG_WRITE:
2000209ff23fSmrg	    val = RADEON_BIOS32(offset);
2001209ff23fSmrg	    ErrorF("PLL_WRITE 0x%x 0x%x\n", index, (unsigned)val);
2002209ff23fSmrg	    OUTPLL(pScrn, index, val);
2003209ff23fSmrg	    offset += 4;
2004209ff23fSmrg	    break;
2005209ff23fSmrg	}
2006209ff23fSmrg    }
2007209ff23fSmrg}
2008209ff23fSmrg
2009209ff23fSmrgBool
2010209ff23fSmrgRADEONPostCardFromBIOSTables(ScrnInfoPtr pScrn)
2011209ff23fSmrg{
2012209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
2013209ff23fSmrg
2014209ff23fSmrg    if (!info->VBIOS) {
2015209ff23fSmrg	return FALSE;
2016209ff23fSmrg    } else {
2017209ff23fSmrg	if (info->IsAtomBios) {
2018209ff23fSmrg	    return FALSE;
2019209ff23fSmrg	} else {
2020209ff23fSmrg	    if (info->BiosTable.rr1_offset) {
2021209ff23fSmrg		ErrorF("rr1 restore, 0x%x\n", info->BiosTable.rr1_offset);
2022209ff23fSmrg		RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr1_offset);
2023209ff23fSmrg	    }
2024209ff23fSmrg	    if (info->BiosTable.revision < 0x09) {
2025209ff23fSmrg		if (info->BiosTable.pll_offset) {
2026209ff23fSmrg		    ErrorF("pll restore, 0x%x\n", info->BiosTable.pll_offset);
2027209ff23fSmrg		    RADEONRestoreBIOSPllBlock(pScrn, info->BiosTable.pll_offset);
2028209ff23fSmrg		}
2029209ff23fSmrg		if (info->BiosTable.rr2_offset) {
2030209ff23fSmrg		    ErrorF("rr2 restore, 0x%x\n", info->BiosTable.rr2_offset);
2031209ff23fSmrg		    RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr2_offset);
2032209ff23fSmrg		}
2033209ff23fSmrg		if (info->BiosTable.rr4_offset) {
2034209ff23fSmrg		    ErrorF("rr4 restore, 0x%x\n", info->BiosTable.rr4_offset);
2035209ff23fSmrg		    RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr4_offset);
2036209ff23fSmrg		}
2037209ff23fSmrg		if (info->BiosTable.mem_reset_offset) {
2038209ff23fSmrg		    ErrorF("mem reset restore, 0x%x\n", info->BiosTable.mem_reset_offset);
2039209ff23fSmrg		    RADEONRestoreBIOSMemBlock(pScrn, info->BiosTable.mem_reset_offset);
2040209ff23fSmrg		}
2041209ff23fSmrg		if (info->BiosTable.rr3_offset) {
2042209ff23fSmrg		    ErrorF("rr3 restore, 0x%x\n", info->BiosTable.rr3_offset);
2043209ff23fSmrg		    RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr3_offset);
2044209ff23fSmrg		}
2045209ff23fSmrg		if (info->BiosTable.dyn_clk_offset) {
2046209ff23fSmrg		    ErrorF("dyn_clk restore, 0x%x\n", info->BiosTable.dyn_clk_offset);
2047209ff23fSmrg		    RADEONRestoreBIOSPllBlock(pScrn, info->BiosTable.dyn_clk_offset);
2048209ff23fSmrg		}
2049209ff23fSmrg	    }
2050209ff23fSmrg	}
2051209ff23fSmrg    }
2052209ff23fSmrg    return TRUE;
2053209ff23fSmrg}
2054