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