1/*
2 * Copyright 2007  Egbert Eich   <eich@novell.com>
3 * Copyright 2007  Luc Verhaegen <lverhaegen@novell.com>
4 * Copyright 2007  Matthias Hopf <mhopf@novell.com>
5 * Copyright 2007  Advanced Micro Devices, Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#ifdef HAVE_CONFIG_H
27# include "config.h"
28#endif
29#include "xf86.h"
30#include "xf86_OSproc.h"
31
32#include "radeon.h"
33#include "radeon_reg.h"
34#include "radeon_atombios.h"
35#include "radeon_atomwrapper.h"
36#include "radeon_probe.h"
37#include "radeon_macros.h"
38
39#include "ati_pciids_gen.h"
40
41#include "xorg-server.h"
42
43/* only for testing now */
44#include "xf86DDC.h"
45
46typedef AtomBiosResult (*AtomBiosRequestFunc)(atomBiosHandlePtr handle,
47					  AtomBiosRequestID unused, AtomBiosArgPtr data);
48typedef struct rhdConnectorInfo *rhdConnectorInfoPtr;
49
50static AtomBiosResult rhdAtomInit(atomBiosHandlePtr unused1,
51				      AtomBiosRequestID unused2, AtomBiosArgPtr data);
52static AtomBiosResult rhdAtomTearDown(atomBiosHandlePtr handle,
53					  AtomBiosRequestID unused1, AtomBiosArgPtr unused2);
54static AtomBiosResult rhdAtomVramInfoQuery(atomBiosHandlePtr handle,
55					       AtomBiosRequestID func, AtomBiosArgPtr data);
56static AtomBiosResult rhdAtomTmdsInfoQuery(atomBiosHandlePtr handle,
57					       AtomBiosRequestID func, AtomBiosArgPtr data);
58static AtomBiosResult rhdAtomAllocateFbScratch(atomBiosHandlePtr handle,
59						   AtomBiosRequestID func, AtomBiosArgPtr data);
60static AtomBiosResult rhdAtomLvdsGetTimings(atomBiosHandlePtr handle,
61					AtomBiosRequestID unused, AtomBiosArgPtr data);
62static AtomBiosResult rhdAtomCVGetTimings(atomBiosHandlePtr handle,
63					  AtomBiosRequestID unused, AtomBiosArgPtr data);
64static AtomBiosResult rhdAtomLvdsInfoQuery(atomBiosHandlePtr handle,
65					       AtomBiosRequestID func,  AtomBiosArgPtr data);
66static AtomBiosResult rhdAtomGPIOI2CInfoQuery(atomBiosHandlePtr handle,
67						  AtomBiosRequestID func, AtomBiosArgPtr data);
68static AtomBiosResult rhdAtomFirmwareInfoQuery(atomBiosHandlePtr handle,
69						   AtomBiosRequestID func, AtomBiosArgPtr data);
70/*static AtomBiosResult rhdAtomConnectorInfo(atomBiosHandlePtr handle,
71  AtomBiosRequestID unused, AtomBiosArgPtr data);*/
72# ifdef ATOM_BIOS_PARSER
73static AtomBiosResult rhdAtomExec(atomBiosHandlePtr handle,
74				   AtomBiosRequestID unused, AtomBiosArgPtr data);
75# endif
76static AtomBiosResult
77rhdAtomCompassionateDataQuery(atomBiosHandlePtr handle,
78			      AtomBiosRequestID func, AtomBiosArgPtr data);
79
80
81static void
82RADEONGetATOMLVDSInfo(ScrnInfoPtr pScrn, radeon_lvds_ptr lvds);
83
84
85enum msgDataFormat {
86    MSG_FORMAT_NONE,
87    MSG_FORMAT_HEX,
88    MSG_FORMAT_DEC
89};
90
91struct atomBIOSRequests {
92    AtomBiosRequestID id;
93    AtomBiosRequestFunc request;
94    char *message;
95    enum msgDataFormat message_format;
96} AtomBiosRequestList [] = {
97    {ATOMBIOS_INIT,			rhdAtomInit,
98     "AtomBIOS Init",				MSG_FORMAT_NONE},
99    {ATOMBIOS_TEARDOWN,			rhdAtomTearDown,
100     "AtomBIOS Teardown",			MSG_FORMAT_NONE},
101# ifdef ATOM_BIOS_PARSER
102    {ATOMBIOS_EXEC,			rhdAtomExec,
103     "AtomBIOS Exec",				MSG_FORMAT_NONE},
104#endif
105    {ATOMBIOS_ALLOCATE_FB_SCRATCH,	rhdAtomAllocateFbScratch,
106     "AtomBIOS Set FB Space",			MSG_FORMAT_NONE},
107    /*{ATOMBIOS_GET_CONNECTORS,		rhdAtomConnectorInfo,
108      "AtomBIOS Get Connectors",			MSG_FORMAT_NONE},*/
109    {ATOMBIOS_GET_PANEL_MODE,		rhdAtomLvdsGetTimings,
110     "AtomBIOS Get Panel Mode",			MSG_FORMAT_NONE},
111    {ATOMBIOS_GET_PANEL_EDID,		rhdAtomLvdsGetTimings,
112     "AtomBIOS Get Panel EDID",			MSG_FORMAT_NONE},
113    {GET_DEFAULT_ENGINE_CLOCK,		rhdAtomFirmwareInfoQuery,
114     "Default Engine Clock",			MSG_FORMAT_DEC},
115    {GET_DEFAULT_MEMORY_CLOCK,		rhdAtomFirmwareInfoQuery,
116     "Default Memory Clock",			MSG_FORMAT_DEC},
117    {GET_MAX_PIXEL_CLOCK_PLL_OUTPUT,	rhdAtomFirmwareInfoQuery,
118     "Maximum Pixel ClockPLL Frequency Output", MSG_FORMAT_DEC},
119    {GET_MIN_PIXEL_CLOCK_PLL_OUTPUT,	rhdAtomFirmwareInfoQuery,
120     "Minimum Pixel ClockPLL Frequency Output", MSG_FORMAT_DEC},
121    {GET_MAX_PIXEL_CLOCK_PLL_INPUT,	rhdAtomFirmwareInfoQuery,
122     "Maximum Pixel ClockPLL Frequency Input", MSG_FORMAT_DEC},
123    {GET_MIN_PIXEL_CLOCK_PLL_INPUT,	rhdAtomFirmwareInfoQuery,
124     "Minimum Pixel ClockPLL Frequency Input", MSG_FORMAT_DEC},
125    {GET_MAX_PIXEL_CLK,			rhdAtomFirmwareInfoQuery,
126     "Maximum Pixel Clock",			MSG_FORMAT_DEC},
127    {GET_REF_CLOCK,			rhdAtomFirmwareInfoQuery,
128     "Reference Clock",				MSG_FORMAT_DEC},
129    {GET_FW_FB_START,			rhdAtomVramInfoQuery,
130      "Start of VRAM area used by Firmware",	MSG_FORMAT_HEX},
131    {GET_FW_FB_SIZE,			rhdAtomVramInfoQuery,
132      "Framebuffer space used by Firmware (kb)", MSG_FORMAT_DEC},
133    {ATOM_TMDS_FREQUENCY,		rhdAtomTmdsInfoQuery,
134     "TMDS Frequency",				MSG_FORMAT_DEC},
135    {ATOM_TMDS_PLL_CHARGE_PUMP,		rhdAtomTmdsInfoQuery,
136     "TMDS PLL ChargePump",			MSG_FORMAT_DEC},
137    {ATOM_TMDS_PLL_DUTY_CYCLE,		rhdAtomTmdsInfoQuery,
138     "TMDS PLL DutyCycle",			MSG_FORMAT_DEC},
139    {ATOM_TMDS_PLL_VCO_GAIN,		rhdAtomTmdsInfoQuery,
140     "TMDS PLL VCO Gain",			MSG_FORMAT_DEC},
141    {ATOM_TMDS_PLL_VOLTAGE_SWING,	rhdAtomTmdsInfoQuery,
142     "TMDS PLL VoltageSwing",			MSG_FORMAT_DEC},
143    {ATOM_LVDS_SUPPORTED_REFRESH_RATE,	rhdAtomLvdsInfoQuery,
144     "LVDS Supported Refresh Rate",		MSG_FORMAT_DEC},
145    {ATOM_LVDS_OFF_DELAY,		rhdAtomLvdsInfoQuery,
146     "LVDS Off Delay",				MSG_FORMAT_DEC},
147    {ATOM_LVDS_SEQ_DIG_ONTO_DE,		rhdAtomLvdsInfoQuery,
148     "LVDS SEQ Dig onto DE",			MSG_FORMAT_DEC},
149    {ATOM_LVDS_SEQ_DE_TO_BL,		rhdAtomLvdsInfoQuery,
150     "LVDS SEQ DE to BL",			MSG_FORMAT_DEC},
151    {ATOM_LVDS_DITHER,			rhdAtomLvdsInfoQuery,
152     "LVDS Ditherc",				MSG_FORMAT_HEX},
153    {ATOM_LVDS_DUALLINK,		rhdAtomLvdsInfoQuery,
154     "LVDS Duallink",				MSG_FORMAT_HEX},
155    {ATOM_LVDS_GREYLVL,			rhdAtomLvdsInfoQuery,
156     "LVDS Grey Level",				MSG_FORMAT_HEX},
157    {ATOM_LVDS_FPDI,			rhdAtomLvdsInfoQuery,
158     "LVDS FPDI",				MSG_FORMAT_HEX},
159    {ATOM_LVDS_24BIT,			rhdAtomLvdsInfoQuery,
160     "LVDS 24Bit",				MSG_FORMAT_HEX},
161    {ATOM_GPIO_I2C_CLK_MASK,		rhdAtomGPIOI2CInfoQuery,
162     "GPIO_I2C_Clk_Mask",			MSG_FORMAT_HEX},
163    {ATOM_DAC1_BG_ADJ,		rhdAtomCompassionateDataQuery,
164     "DAC1 BG Adjustment",			MSG_FORMAT_HEX},
165    {ATOM_DAC1_DAC_ADJ,		rhdAtomCompassionateDataQuery,
166     "DAC1 DAC Adjustment",			MSG_FORMAT_HEX},
167    {ATOM_DAC1_FORCE,		rhdAtomCompassionateDataQuery,
168     "DAC1 Force Data",				MSG_FORMAT_HEX},
169    {ATOM_DAC2_CRTC2_BG_ADJ,	rhdAtomCompassionateDataQuery,
170     "DAC2_CRTC2 BG Adjustment",		MSG_FORMAT_HEX},
171    {ATOM_DAC2_CRTC2_DAC_ADJ,	rhdAtomCompassionateDataQuery,
172     "DAC2_CRTC2 DAC Adjustment",		MSG_FORMAT_HEX},
173    {ATOM_DAC2_CRTC2_FORCE,	rhdAtomCompassionateDataQuery,
174     "DAC2_CRTC2 Force",			MSG_FORMAT_HEX},
175    {ATOM_DAC2_CRTC2_MUX_REG_IND,rhdAtomCompassionateDataQuery,
176     "DAC2_CRTC2 Mux Register Index",		MSG_FORMAT_HEX},
177    {ATOM_DAC2_CRTC2_MUX_REG_INFO,rhdAtomCompassionateDataQuery,
178     "DAC2_CRTC2 Mux Register Info",		MSG_FORMAT_HEX},
179    {ATOMBIOS_GET_CV_MODES,		rhdAtomCVGetTimings,
180     "AtomBIOS Get CV Mode",			MSG_FORMAT_NONE},
181    {FUNC_END,					NULL,
182     NULL,					MSG_FORMAT_NONE}
183};
184
185enum {
186    legacyBIOSLocation = 0xC0000,
187    legacyBIOSMax = 0x10000
188};
189
190#define DEBUGP(x) {x;}
191#define LOG_DEBUG 7
192
193#  ifdef ATOM_BIOS_PARSER
194
195#   define LOG_CAIL LOG_DEBUG + 1
196
197#if 0
198
199static void
200RHDDebug(int scrnIndex, const char *format, ...)
201{
202    va_list ap;
203
204    va_start(ap, format);
205    xf86VDrvMsgVerb(scrnIndex, X_INFO, LOG_DEBUG, format, ap);
206    va_end(ap);
207}
208
209static void
210RHDDebugCont(const char *format, ...)
211{
212    va_list ap;
213
214    va_start(ap, format);
215    xf86VDrvMsgVerb(-1, X_NONE, LOG_DEBUG, format, ap);
216    va_end(ap);
217}
218
219#endif
220
221static void
222CailDebug(int scrnIndex, const char *format, ...)
223{
224    va_list ap;
225
226    va_start(ap, format);
227    xf86VDrvMsgVerb(scrnIndex, X_INFO, LOG_CAIL, format, ap);
228    va_end(ap);
229}
230#   define CAILFUNC(ptr) \
231  CailDebug(((atomBiosHandlePtr)(ptr))->pScrn->scrnIndex, "CAIL: %s\n", __func__)
232
233#  endif
234
235static int
236rhdAtomAnalyzeCommonHdr(ATOM_COMMON_TABLE_HEADER *hdr)
237{
238    if (le16_to_cpu(hdr->usStructureSize) == 0xaa55)
239        return FALSE;
240
241    return TRUE;
242}
243
244static int
245rhdAtomAnalyzeRomHdr(unsigned char *rombase,
246		     ATOM_ROM_HEADER *hdr,
247		     unsigned int *data_offset,
248		     unsigned int *command_offset)
249{
250    if (!rhdAtomAnalyzeCommonHdr(&hdr->sHeader)) {
251        return FALSE;
252    }
253    xf86DrvMsg(-1,X_NONE,"\tSubsystemVendorID: 0x%4.4x SubsystemID: 0x%4.4x\n",
254               le16_to_cpu(hdr->usSubsystemVendorID),le16_to_cpu(hdr->usSubsystemID));
255    xf86DrvMsg(-1,X_NONE,"\tIOBaseAddress: 0x%4.4x\n",le16_to_cpu(hdr->usIoBaseAddress));
256    xf86DrvMsgVerb(-1,X_NONE,3,"\tFilename: %s\n",rombase + le16_to_cpu(hdr->usConfigFilenameOffset));
257    xf86DrvMsgVerb(-1,X_NONE,3,"\tBIOS Bootup Message: %s\n",
258		   rombase + le16_to_cpu(hdr->usBIOS_BootupMessageOffset));
259
260    *data_offset = le16_to_cpu(hdr->usMasterDataTableOffset);
261    *command_offset = le16_to_cpu(hdr->usMasterCommandTableOffset);
262
263    return TRUE;
264}
265
266static int
267rhdAtomAnalyzeRomDataTable(unsigned char *base, uint16_t offset,
268                    void *ptr,unsigned short *size)
269{
270    ATOM_COMMON_TABLE_HEADER *table = (ATOM_COMMON_TABLE_HEADER *)
271      (base + le16_to_cpu(offset));
272
273   if (!*size || !rhdAtomAnalyzeCommonHdr(table)) {
274       if (*size) *size -= 2;
275       *(void **)ptr = NULL;
276       return FALSE;
277   }
278   *size -= 2;
279   *(void **)ptr = (void *)(table);
280   return TRUE;
281}
282
283Bool
284rhdAtomGetTableRevisionAndSize(ATOM_COMMON_TABLE_HEADER *hdr,
285			       uint8_t *contentRev,
286			       uint8_t *formatRev,
287			       unsigned short *size)
288{
289    if (!hdr)
290        return FALSE;
291
292    if (contentRev) *contentRev = hdr->ucTableContentRevision;
293    if (formatRev) *formatRev = hdr->ucTableFormatRevision;
294    if (size) *size = (short)le16_to_cpu(hdr->usStructureSize)
295                   - sizeof(ATOM_COMMON_TABLE_HEADER);
296    return TRUE;
297}
298
299static Bool
300rhdAtomAnalyzeMasterDataTable(unsigned char *base,
301			      ATOM_MASTER_DATA_TABLE *table,
302			      atomDataTablesPtr data)
303{
304    ATOM_MASTER_LIST_OF_DATA_TABLES *data_table =
305        &table->ListOfDataTables;
306    unsigned short size;
307
308    if (!rhdAtomAnalyzeCommonHdr(&table->sHeader))
309        return FALSE;
310    if (!rhdAtomGetTableRevisionAndSize(&table->sHeader,NULL,NULL,
311					&size))
312        return FALSE;
313# define SET_DATA_TABLE(x) {\
314   rhdAtomAnalyzeRomDataTable(base,data_table->x,(void *)(&(data->x)),&size); \
315    }
316
317# define SET_DATA_TABLE_VERS(x) {\
318   rhdAtomAnalyzeRomDataTable(base,data_table->x,&(data->x.base),&size); \
319    }
320
321    SET_DATA_TABLE(UtilityPipeLine);
322    SET_DATA_TABLE(MultimediaCapabilityInfo);
323    SET_DATA_TABLE(MultimediaConfigInfo);
324    SET_DATA_TABLE(StandardVESA_Timing);
325    SET_DATA_TABLE_VERS(FirmwareInfo);
326    SET_DATA_TABLE(DAC_Info);
327    SET_DATA_TABLE_VERS(LVDS_Info);
328    SET_DATA_TABLE(TMDS_Info);
329    SET_DATA_TABLE_VERS(AnalogTV_Info);
330    SET_DATA_TABLE_VERS(SupportedDevicesInfo);
331    SET_DATA_TABLE(GPIO_I2C_Info);
332    SET_DATA_TABLE(VRAM_UsageByFirmware);
333    SET_DATA_TABLE(GPIO_Pin_LUT);
334    SET_DATA_TABLE(VESA_ToInternalModeLUT);
335    SET_DATA_TABLE_VERS(ComponentVideoInfo);
336    SET_DATA_TABLE(PowerPlayInfo);
337    SET_DATA_TABLE(CompassionateData);
338    SET_DATA_TABLE(SaveRestoreInfo);
339    SET_DATA_TABLE(PPLL_SS_Info);
340    SET_DATA_TABLE(OemInfo);
341    SET_DATA_TABLE(XTMDS_Info);
342    SET_DATA_TABLE(MclkSS_Info);
343    SET_DATA_TABLE(Object_Header);
344    SET_DATA_TABLE(IndirectIOAccess);
345    SET_DATA_TABLE(MC_InitParameter);
346    SET_DATA_TABLE(ASIC_VDDC_Info);
347    SET_DATA_TABLE(ASIC_InternalSS_Info);
348    SET_DATA_TABLE(TV_VideoMode);
349    SET_DATA_TABLE_VERS(VRAM_Info);
350    SET_DATA_TABLE(MemoryTrainingInfo);
351    SET_DATA_TABLE_VERS(IntegratedSystemInfo);
352    SET_DATA_TABLE(ASIC_ProfilingInfo);
353    SET_DATA_TABLE(VoltageObjectInfo);
354    SET_DATA_TABLE(PowerSourceInfo);
355# undef SET_DATA_TABLE
356
357    return TRUE;
358}
359
360static Bool
361rhdAtomGetDataTable(int scrnIndex,
362		    unsigned char *base,
363		    atomDataTables *atomDataPtr,
364		    unsigned int *cmd_offset,
365		    unsigned int BIOSImageSize)
366{
367    unsigned int data_offset;
368    unsigned int atom_romhdr_off =  le16_to_cpu(*(unsigned short*)
369        (base + OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER));
370    ATOM_ROM_HEADER *atom_rom_hdr =
371        (ATOM_ROM_HEADER *)(base + atom_romhdr_off);
372
373    //RHDFUNCI(scrnIndex);
374
375    if (atom_romhdr_off + sizeof(ATOM_ROM_HEADER) > BIOSImageSize) {
376	xf86DrvMsg(scrnIndex,X_ERROR,
377		   "%s: AtomROM header extends beyond BIOS image\n",__func__);
378	return FALSE;
379    }
380
381    if (memcmp("ATOM",&atom_rom_hdr->uaFirmWareSignature,4)) {
382        xf86DrvMsg(scrnIndex,X_ERROR,"%s: No AtomBios signature found\n",
383		   __func__);
384        return FALSE;
385    }
386    xf86DrvMsg(scrnIndex, X_INFO, "ATOM BIOS Rom: \n");
387    if (!rhdAtomAnalyzeRomHdr(base, atom_rom_hdr, &data_offset, cmd_offset)) {
388        xf86DrvMsg(scrnIndex, X_ERROR, "RomHeader invalid\n");
389        return FALSE;
390    }
391
392    if (data_offset + sizeof (ATOM_MASTER_DATA_TABLE) > BIOSImageSize) {
393	xf86DrvMsg(scrnIndex,X_ERROR,"%s: Atom data table outside of BIOS\n",
394		   __func__);
395    }
396
397    if (*cmd_offset + sizeof (ATOM_MASTER_COMMAND_TABLE) > BIOSImageSize) {
398	xf86DrvMsg(scrnIndex,X_ERROR,"%s: Atom command table outside of BIOS\n",
399		   __func__);
400    }
401
402    if (!rhdAtomAnalyzeMasterDataTable(base, (ATOM_MASTER_DATA_TABLE *)
403				       (base + data_offset),
404				       atomDataPtr)) {
405        xf86DrvMsg(scrnIndex, X_ERROR, "%s: ROM Master Table invalid\n",
406		   __func__);
407        return FALSE;
408    }
409    return TRUE;
410}
411
412static Bool
413rhdAtomGetFbBaseAndSize(atomBiosHandlePtr handle, unsigned int *base,
414			unsigned int *size)
415{
416    AtomBiosArgRec data;
417    if (RHDAtomBiosFunc(handle->pScrn, handle, GET_FW_FB_SIZE, &data)
418	== ATOM_SUCCESS) {
419	if (data.val == 0) {
420	    xf86DrvMsg(handle->pScrn->scrnIndex, X_WARNING, "%s: AtomBIOS specified VRAM "
421		       "scratch space size invalid\n", __func__);
422	    return FALSE;
423	}
424	if (size)
425	    *size = (int)data.val;
426    } else
427	return FALSE;
428    if (RHDAtomBiosFunc(handle->pScrn, handle, GET_FW_FB_START, &data)
429	== ATOM_SUCCESS) {
430	if (data.val == 0)
431	    return FALSE;
432	if (base)
433	    *base = (int)data.val;
434    }
435    return TRUE;
436}
437
438/*
439 * Uses videoRam form ScrnInfoRec.
440 */
441static AtomBiosResult
442rhdAtomAllocateFbScratch(atomBiosHandlePtr handle,
443			 AtomBiosRequestID func, AtomBiosArgPtr data)
444{
445    unsigned int fb_base = 0;
446    unsigned int fb_size = 0;
447    unsigned int start = data->fb.start;
448    unsigned int size = data->fb.size;
449    handle->scratchBase = NULL;
450    handle->fbBase = 0;
451
452    if (rhdAtomGetFbBaseAndSize(handle, &fb_base, &fb_size)) {
453	xf86DrvMsg(handle->pScrn->scrnIndex, X_INFO, "AtomBIOS requests %ikB"
454		   " of VRAM scratch space\n",fb_size);
455	fb_size *= 1024; /* convert to bytes */
456	xf86DrvMsg(handle->pScrn->scrnIndex, X_INFO, "AtomBIOS VRAM scratch base: 0x%x\n",
457		   fb_base);
458    } else {
459	    fb_size = 20 * 1024;
460	    xf86DrvMsg(handle->pScrn->scrnIndex, X_INFO, " default to: %i\n",fb_size);
461    }
462    if (fb_base && fb_size && size) {
463	/* 4k align */
464	fb_size = (fb_size & ~(uint32_t)0xfff) + ((fb_size & 0xfff) ? 1 : 0);
465	if ((fb_base + fb_size) > (start + size)) {
466	    xf86DrvMsg(handle->pScrn->scrnIndex, X_WARNING,
467		       "%s: FW FB scratch area %i (size: %i)"
468		       " extends beyond available framebuffer size %i\n",
469		       __func__, fb_base, fb_size, size);
470	} else if ((fb_base + fb_size) < (start + size)) {
471	    xf86DrvMsg(handle->pScrn->scrnIndex, X_WARNING,
472		       "%s: FW FB scratch area not located "
473		       "at the end of VRAM. Scratch End: "
474		       "0x%x VRAM End: 0x%x\n", __func__,
475		       (unsigned int)(fb_base + fb_size),
476		       size);
477	} else if (fb_base < start) {
478	    xf86DrvMsg(handle->pScrn->scrnIndex, X_WARNING,
479		       "%s: FW FB scratch area extends below "
480		       "the base of the free VRAM: 0x%x Base: 0x%x\n",
481		       __func__, (unsigned int)(fb_base), start);
482	} else {
483	    size -= fb_size;
484	    handle->fbBase = fb_base;
485	    return ATOM_SUCCESS;
486	}
487    }
488
489    if (!handle->fbBase) {
490	xf86DrvMsg(handle->pScrn->scrnIndex, X_INFO,
491		   "Cannot get VRAM scratch space. "
492		   "Allocating in main memory instead\n");
493	handle->scratchBase = calloc(fb_size,1);
494	return ATOM_SUCCESS;
495    }
496    return ATOM_FAILED;
497}
498
499# ifdef ATOM_BIOS_PARSER
500Bool
501rhdAtomASICInit(atomBiosHandlePtr handle)
502{
503    ASIC_INIT_PS_ALLOCATION asicInit;
504    AtomBiosArgRec data;
505
506    RHDAtomBiosFunc(handle->pScrn, handle,
507		    GET_DEFAULT_ENGINE_CLOCK,
508		    &data);
509    asicInit.sASICInitClocks.ulDefaultEngineClock = cpu_to_le32(data.val / 10);/*in 10 Khz*/
510    RHDAtomBiosFunc(handle->pScrn, handle,
511		    GET_DEFAULT_MEMORY_CLOCK,
512		    &data);
513    asicInit.sASICInitClocks.ulDefaultMemoryClock = cpu_to_le32(data.val / 10);/*in 10 Khz*/
514    data.exec.dataSpace = NULL;
515    data.exec.index = 0x0;
516    data.exec.pspace = &asicInit;
517    xf86DrvMsg(handle->pScrn->scrnIndex, X_INFO, "Calling ASIC Init\n");
518    if (RHDAtomBiosFunc(handle->pScrn, handle,
519			ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
520	xf86DrvMsg(handle->pScrn->scrnIndex, X_INFO, "ASIC_INIT Successful\n");
521	return TRUE;
522    }
523    xf86DrvMsg(handle->pScrn->scrnIndex, X_INFO, "ASIC_INIT Failed\n");
524    return FALSE;
525}
526
527int
528atombios_clk_gating_setup(ScrnInfoPtr pScrn, Bool enable)
529{
530    RADEONInfoPtr info       = RADEONPTR(pScrn);
531    DYNAMIC_CLOCK_GATING_PS_ALLOCATION dynclk_data;
532    AtomBiosArgRec data;
533    unsigned char *space;
534
535    dynclk_data.ucEnable = enable;
536
537    data.exec.index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);
538    data.exec.dataSpace = (void *)&space;
539    data.exec.pspace = &dynclk_data;
540
541    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
542	ErrorF("Dynamic clock gating %s success\n", enable? "enable" : "disable");
543	return ATOM_SUCCESS;
544    }
545
546    ErrorF("Dynamic clock gating %s failure\n", enable? "enable" : "disable");
547    return ATOM_NOT_IMPLEMENTED;
548
549}
550
551int
552atombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, Bool enable)
553{
554    RADEONInfoPtr info       = RADEONPTR(pScrn);
555    ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION pwrmgt_data;
556    AtomBiosArgRec data;
557    unsigned char *space;
558
559    /* disabling static power management causes hangs on some r4xx chips */
560    if (((info->ChipFamily == CHIP_FAMILY_R420) ||
561	 (info->ChipFamily == CHIP_FAMILY_RV410)) &&
562	!enable)
563	return ATOM_NOT_IMPLEMENTED;
564
565    pwrmgt_data.ucEnable = enable;
566
567    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableASIC_StaticPwrMgt);
568    data.exec.dataSpace = (void *)&space;
569    data.exec.pspace = &pwrmgt_data;
570
571    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
572	ErrorF("Static power management %s success\n", enable? "enable" : "disable");
573	return ATOM_SUCCESS;
574    }
575
576    ErrorF("Static power management %s failure\n", enable? "enable" : "disable");
577    return ATOM_NOT_IMPLEMENTED;
578
579}
580
581int
582atombios_set_engine_clock(ScrnInfoPtr pScrn, uint32_t engclock)
583{
584    RADEONInfoPtr info       = RADEONPTR(pScrn);
585    SET_ENGINE_CLOCK_PS_ALLOCATION eng_clock_ps;
586    AtomBiosArgRec data;
587    unsigned char *space;
588
589    RADEONWaitForIdleMMIO(pScrn);
590
591    eng_clock_ps.ulTargetEngineClock = engclock; /* 10 khz */
592
593    /*ErrorF("Attempting to set engine clock to: %d\n", engclock);*/
594    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
595    data.exec.dataSpace = (void *)&space;
596    data.exec.pspace = &eng_clock_ps;
597
598    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
599	/* ErrorF("Set engine clock success\n"); */
600	return ATOM_SUCCESS;
601    }
602    /* ErrorF("Set engine clock failed\n"); */
603    return ATOM_NOT_IMPLEMENTED;
604}
605
606int
607atombios_set_memory_clock(ScrnInfoPtr pScrn, uint32_t memclock)
608{
609    RADEONInfoPtr info       = RADEONPTR(pScrn);
610    SET_MEMORY_CLOCK_PS_ALLOCATION mem_clock_ps;
611    AtomBiosArgRec data;
612    unsigned char *space;
613
614    if (info->IsIGP)
615	return ATOM_SUCCESS;
616
617    RADEONWaitForIdleMMIO(pScrn);
618
619    mem_clock_ps.ulTargetMemoryClock = memclock; /* 10 khz */
620
621    /* ErrorF("Attempting to set mem clock to: %d\n", memclock); */
622    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
623    data.exec.dataSpace = (void *)&space;
624    data.exec.pspace = &mem_clock_ps;
625
626    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
627	/* ErrorF("Set memory clock success\n"); */
628	return ATOM_SUCCESS;
629    }
630    /* ErrorF("Set memory clock failed\n"); */
631    return ATOM_NOT_IMPLEMENTED;
632}
633
634# endif
635
636static AtomBiosResult
637rhdAtomInit(atomBiosHandlePtr unused1, AtomBiosRequestID unused2,
638		    AtomBiosArgPtr data)
639{
640    ScrnInfoPtr pScrn = data->pScrn;
641    RADEONInfoPtr  info   = RADEONPTR(pScrn);
642    atomDataTablesPtr atomDataPtr;
643    unsigned int cmd_offset;
644    atomBiosHandlePtr handle = NULL;
645    unsigned int BIOSImageSize = 0;
646    data->atomhandle = NULL;
647
648#ifdef XSERVER_LIBPCIACCESS
649    BIOSImageSize = info->PciInfo->rom_size > RADEON_VBIOS_SIZE ? info->PciInfo->rom_size : RADEON_VBIOS_SIZE;
650#else
651    BIOSImageSize = RADEON_VBIOS_SIZE;
652#endif
653
654    if (!(atomDataPtr = calloc(1, sizeof(atomDataTables)))) {
655	xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Cannot allocate memory for "
656		   "ATOM BIOS data tabes\n");
657	goto error;
658    }
659    if (!rhdAtomGetDataTable(pScrn->scrnIndex, info->VBIOS, atomDataPtr, &cmd_offset, BIOSImageSize))
660	goto error1;
661    if (!(handle = calloc(1, sizeof(atomBiosHandleRec)))) {
662	xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Cannot allocate memory\n");
663	goto error1;
664    }
665    handle->BIOSBase = info->VBIOS;
666    handle->atomDataPtr = atomDataPtr;
667    handle->cmd_offset = cmd_offset;
668    handle->pScrn = pScrn;
669#if XSERVER_LIBPCIACCESS
670    handle->device = info->PciInfo;
671#else
672    handle->PciTag = info->PciTag;
673#endif
674    handle->BIOSImageSize = BIOSImageSize;
675
676    data->atomhandle = handle;
677    return ATOM_SUCCESS;
678
679 error1:
680    free(atomDataPtr);
681 error:
682    return ATOM_FAILED;
683}
684
685static AtomBiosResult
686rhdAtomTearDown(atomBiosHandlePtr handle,
687		AtomBiosRequestID unused1, AtomBiosArgPtr unused2)
688{
689    //RHDFUNC(handle);
690
691    free(handle->BIOSBase);
692    free(handle->atomDataPtr);
693    if (handle->scratchBase) free(handle->scratchBase);
694    free(handle);
695    return ATOM_SUCCESS;
696}
697
698static AtomBiosResult
699rhdAtomVramInfoQuery(atomBiosHandlePtr handle, AtomBiosRequestID func,
700		     AtomBiosArgPtr data)
701{
702    atomDataTablesPtr atomDataPtr;
703    uint32_t *val = &data->val;
704    //RHDFUNC(handle);
705
706    atomDataPtr = handle->atomDataPtr;
707
708    switch (func) {
709	case GET_FW_FB_START:
710	    if (atomDataPtr->VRAM_UsageByFirmware)
711		*val = le32_to_cpu(atomDataPtr->VRAM_UsageByFirmware
712				   ->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware);
713	    else
714		return ATOM_NOT_IMPLEMENTED;
715	    break;
716	case GET_FW_FB_SIZE:
717	    if (atomDataPtr->VRAM_UsageByFirmware)
718		*val =  le16_to_cpu(atomDataPtr->VRAM_UsageByFirmware
719				    ->asFirmwareVramReserveInfo[0].usFirmwareUseInKb);
720	    else
721		return ATOM_NOT_IMPLEMENTED;
722	    break;
723	default:
724	    return ATOM_NOT_IMPLEMENTED;
725    }
726    return ATOM_SUCCESS;
727}
728
729static AtomBiosResult
730rhdAtomTmdsInfoQuery(atomBiosHandlePtr handle,
731		     AtomBiosRequestID func, AtomBiosArgPtr data)
732{
733    atomDataTablesPtr atomDataPtr;
734    uint32_t *val = &data->val;
735    int idx = *val;
736
737    atomDataPtr = handle->atomDataPtr;
738    if (!rhdAtomGetTableRevisionAndSize(
739	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->TMDS_Info),
740	    NULL,NULL,NULL)) {
741	return ATOM_FAILED;
742    }
743
744    //RHDFUNC(handle);
745
746    switch (func) {
747	case ATOM_TMDS_FREQUENCY:
748	    *val = le16_to_cpu(atomDataPtr->TMDS_Info->asMiscInfo[idx].usFrequency);
749	    break;
750	case ATOM_TMDS_PLL_CHARGE_PUMP:
751	    *val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_ChargePump;
752	    break;
753	case ATOM_TMDS_PLL_DUTY_CYCLE:
754	    *val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_DutyCycle;
755	    break;
756	case ATOM_TMDS_PLL_VCO_GAIN:
757	    *val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_VCO_Gain;
758	    break;
759	case ATOM_TMDS_PLL_VOLTAGE_SWING:
760	    *val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_VoltageSwing;
761	    break;
762	default:
763	    return ATOM_NOT_IMPLEMENTED;
764    }
765    return ATOM_SUCCESS;
766}
767
768static DisplayModePtr
769rhdAtomDTDTimings(atomBiosHandlePtr handle, ATOM_DTD_FORMAT *dtd)
770{
771    DisplayModePtr mode;
772#define NAME_LEN 16
773    char name[NAME_LEN];
774
775    //RHDFUNC(handle);
776
777    if (!dtd->usHActive || !dtd->usVActive)
778	return NULL;
779
780    if (!(mode = (DisplayModePtr)calloc(1,sizeof(DisplayModeRec))))
781	return NULL;
782
783    mode->CrtcHDisplay = mode->HDisplay = le16_to_cpu(dtd->usHActive);
784    mode->CrtcVDisplay = mode->VDisplay = le16_to_cpu(dtd->usVActive);
785    mode->CrtcHBlankStart = le16_to_cpu(dtd->usHActive) + dtd->ucHBorder;
786    mode->CrtcHBlankEnd = mode->CrtcHBlankStart + le16_to_cpu(dtd->usHBlanking_Time);
787    mode->CrtcHTotal = mode->HTotal = mode->CrtcHBlankEnd + dtd->ucHBorder;
788    mode->CrtcVBlankStart = le16_to_cpu(dtd->usVActive) + dtd->ucVBorder;
789    mode->CrtcVBlankEnd = mode->CrtcVBlankStart + le16_to_cpu(dtd->usVBlanking_Time);
790    mode->CrtcVTotal = mode->VTotal = mode->CrtcVBlankEnd + dtd->ucVBorder;
791    mode->CrtcHSyncStart = mode->HSyncStart = le16_to_cpu(dtd->usHActive) + le16_to_cpu(dtd->usHSyncOffset);
792    mode->CrtcHSyncEnd = mode->HSyncEnd = mode->HSyncStart + le16_to_cpu(dtd->usHSyncWidth);
793    mode->CrtcVSyncStart = mode->VSyncStart = le16_to_cpu(dtd->usVActive) + le16_to_cpu(dtd->usVSyncOffset);
794    mode->CrtcVSyncEnd = mode->VSyncEnd = mode->VSyncStart + le16_to_cpu(dtd->usVSyncWidth);
795
796    mode->SynthClock = mode->Clock = le16_to_cpu(dtd->usPixClk) * 10;
797
798    mode->HSync = ((float) mode->Clock) / ((float)mode->HTotal);
799    mode->VRefresh = (1000.0 * ((float) mode->Clock))
800	/ ((float)(((float)mode->HTotal) * ((float)mode->VTotal)));
801
802    if (dtd->susModeMiscInfo.sbfAccess.CompositeSync)
803	mode->Flags |= V_CSYNC;
804    if (dtd->susModeMiscInfo.sbfAccess.Interlace)
805	mode->Flags |= V_INTERLACE;
806    if (dtd->susModeMiscInfo.sbfAccess.DoubleClock)
807	mode->Flags |= V_DBLSCAN;
808    if (dtd->susModeMiscInfo.sbfAccess.VSyncPolarity)
809	mode->Flags |= V_NVSYNC;
810    if (dtd->susModeMiscInfo.sbfAccess.HSyncPolarity)
811	mode->Flags |= V_NHSYNC;
812
813    snprintf(name, NAME_LEN, "%dx%d",
814	     mode->HDisplay, mode->VDisplay);
815    mode->name = xstrdup(name);
816
817    ErrorF("DTD Modeline: %s  "
818	   "%2.d  %i (%i) %i %i (%i) %i  %i (%i) %i %i (%i) %i flags: 0x%x\n",
819	   mode->name, mode->Clock,
820	   mode->HDisplay, mode->CrtcHBlankStart, mode->HSyncStart, mode->CrtcHSyncEnd,
821	   mode->CrtcHBlankEnd, mode->HTotal,
822	   mode->VDisplay, mode->CrtcVBlankStart, mode->VSyncStart, mode->VSyncEnd,
823	   mode->CrtcVBlankEnd, mode->VTotal, mode->Flags);
824
825    return mode;
826}
827
828static unsigned char*
829rhdAtomLvdsDDC(atomBiosHandlePtr handle, uint32_t offset, unsigned char *record)
830{
831    unsigned char *EDIDBlock;
832
833    //RHDFUNC(handle);
834
835    while (*record != ATOM_RECORD_END_TYPE) {
836
837	switch (*record) {
838	    case LCD_MODE_PATCH_RECORD_MODE_TYPE:
839		offset += sizeof(ATOM_PATCH_RECORD_MODE);
840		if (offset > handle->BIOSImageSize) break;
841		record += sizeof(ATOM_PATCH_RECORD_MODE);
842		break;
843
844	    case LCD_RTS_RECORD_TYPE:
845		offset += sizeof(ATOM_LCD_RTS_RECORD);
846		if (offset > handle->BIOSImageSize) break;
847		record += sizeof(ATOM_LCD_RTS_RECORD);
848		break;
849
850	    case LCD_CAP_RECORD_TYPE:
851		offset += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
852		if (offset > handle->BIOSImageSize) break;
853		record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
854		break;
855
856	    case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
857		offset += sizeof(ATOM_FAKE_EDID_PATCH_RECORD);
858		/* check if the structure still fully lives in the BIOS image */
859		if (offset > handle->BIOSImageSize) break;
860		offset += ((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDLength
861		    - sizeof(UCHAR);
862		if (offset > handle->BIOSImageSize) break;
863		/* dup string as we free it later */
864		if (!(EDIDBlock = (unsigned char *)malloc(
865			  ((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDLength)))
866		    return NULL;
867		memcpy(EDIDBlock,&((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDString,
868		       ((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDLength);
869
870		/* for testing */
871		{
872		    xf86MonPtr mon = xf86InterpretEDID(handle->pScrn->scrnIndex,EDIDBlock);
873		    xf86PrintEDID(mon);
874		    free(mon);
875		}
876		return EDIDBlock;
877
878	    case LCD_PANEL_RESOLUTION_RECORD_TYPE:
879		offset += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
880		if (offset > handle->BIOSImageSize) break;
881		record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
882		break;
883
884	    default:
885		xf86DrvMsg(handle->pScrn->scrnIndex, X_ERROR,
886			   "%s: unknown record type: %x\n",__func__,*record);
887		return NULL;
888	}
889    }
890
891    return NULL;
892}
893
894static AtomBiosResult
895rhdAtomCVGetTimings(atomBiosHandlePtr handle, AtomBiosRequestID func,
896		    AtomBiosArgPtr data)
897{
898    atomDataTablesPtr atomDataPtr;
899    uint8_t crev, frev;
900    DisplayModePtr  last       = NULL;
901    DisplayModePtr  new        = NULL;
902    DisplayModePtr  first      = NULL;
903    int i;
904    uint16_t size;
905
906    data->modes = NULL;
907
908    atomDataPtr = handle->atomDataPtr;
909
910    if (!rhdAtomGetTableRevisionAndSize(
911	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->ComponentVideoInfo.base),
912	    &crev,&frev,&size)) {
913	return ATOM_FAILED;
914    }
915
916    switch (frev) {
917	case 1:
918	    switch (func) {
919		case ATOMBIOS_GET_CV_MODES:
920		    for (i = 0; i < MAX_SUPPORTED_CV_STANDARDS; i++) {
921			new = rhdAtomDTDTimings(handle,
922						&atomDataPtr->ComponentVideoInfo
923						.ComponentVideoInfo->aModeTimings[i]);
924
925			if (!new)
926			    continue;
927
928			new->type      |= M_T_DRIVER;
929			new->next       = NULL;
930			new->prev       = last;
931
932			if (last) last->next = new;
933			last = new;
934			if (!first) first = new;
935		    }
936		    if (last) {
937			last->next   = NULL; //first;
938			first->prev  = NULL; //last;
939			data->modes = first;
940		    }
941		    if (data->modes)
942			return ATOM_SUCCESS;
943		default:
944		    return ATOM_FAILED;
945	    }
946	case 2:
947	    switch (func) {
948		case ATOMBIOS_GET_CV_MODES:
949		    for (i = 0; i < MAX_SUPPORTED_CV_STANDARDS; i++) {
950		        /* my rv730 table has only room for one mode */
951		        if ((void *)&atomDataPtr->ComponentVideoInfo.ComponentVideoInfo_v21->aModeTimings[i] -
952			    atomDataPtr->ComponentVideoInfo.base > size)
953			    break;
954
955			new = rhdAtomDTDTimings(handle,
956						&atomDataPtr->ComponentVideoInfo
957						.ComponentVideoInfo_v21->aModeTimings[i]);
958
959			if (!new)
960			    continue;
961
962			new->type      |= M_T_DRIVER;
963			new->next       = NULL;
964			new->prev       = last;
965
966			if (last) last->next = new;
967			last = new;
968			if (!first) first = new;
969
970		    }
971		    if (last) {
972			last->next   = NULL; //first;
973			first->prev  = NULL; //last;
974			data->modes = first;
975		    }
976		    if (data->modes)
977			return ATOM_SUCCESS;
978		    return ATOM_FAILED;
979
980		default:
981		    return ATOM_FAILED;
982	    }
983	default:
984	    return ATOM_NOT_IMPLEMENTED;
985    }
986/*NOTREACHED*/
987}
988
989static AtomBiosResult
990rhdAtomLvdsGetTimings(atomBiosHandlePtr handle, AtomBiosRequestID func,
991		    AtomBiosArgPtr data)
992{
993    atomDataTablesPtr atomDataPtr;
994    uint8_t crev, frev;
995    unsigned long offset;
996
997    //RHDFUNC(handle);
998
999    atomDataPtr = handle->atomDataPtr;
1000
1001    if (!rhdAtomGetTableRevisionAndSize(
1002	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
1003	    &frev,&crev,NULL)) {
1004	return ATOM_FAILED;
1005    }
1006
1007    switch (crev) {
1008
1009	case 1:
1010	    switch (func) {
1011		case ATOMBIOS_GET_PANEL_MODE:
1012		    data->modes = rhdAtomDTDTimings(handle,
1013						   &atomDataPtr->LVDS_Info
1014						   .LVDS_Info->sLCDTiming);
1015		    if (data->modes)
1016			return ATOM_SUCCESS;
1017		default:
1018		    return ATOM_FAILED;
1019	    }
1020	case 2:
1021	    switch (func) {
1022		case ATOMBIOS_GET_PANEL_MODE:
1023		    data->modes = rhdAtomDTDTimings(handle,
1024						   &atomDataPtr->LVDS_Info
1025						   .LVDS_Info_v12->sLCDTiming);
1026		    if (data->modes)
1027			return ATOM_SUCCESS;
1028		    return ATOM_FAILED;
1029
1030		case ATOMBIOS_GET_PANEL_EDID:
1031		    offset = (unsigned long)&atomDataPtr->LVDS_Info.base
1032			- (unsigned long)handle->BIOSBase
1033			+ le16_to_cpu(atomDataPtr->LVDS_Info
1034			.LVDS_Info_v12->usExtInfoTableOffset);
1035
1036		    data->EDIDBlock
1037			= rhdAtomLvdsDDC(handle, offset,
1038					 (unsigned char *)
1039					 &atomDataPtr->LVDS_Info.base
1040					 + le16_to_cpu(atomDataPtr->LVDS_Info
1041					 .LVDS_Info_v12->usExtInfoTableOffset));
1042		    if (data->EDIDBlock)
1043			return ATOM_SUCCESS;
1044		default:
1045		    return ATOM_FAILED;
1046	    }
1047	default:
1048	    return ATOM_NOT_IMPLEMENTED;
1049    }
1050/*NOTREACHED*/
1051}
1052
1053static AtomBiosResult
1054rhdAtomLvdsInfoQuery(atomBiosHandlePtr handle,
1055		     AtomBiosRequestID func,  AtomBiosArgPtr data)
1056{
1057    atomDataTablesPtr atomDataPtr;
1058    uint8_t crev, frev;
1059    uint32_t *val = &data->val;
1060
1061    //RHDFUNC(handle);
1062
1063    atomDataPtr = handle->atomDataPtr;
1064
1065    if (!rhdAtomGetTableRevisionAndSize(
1066	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
1067	    &frev,&crev,NULL)) {
1068	return ATOM_FAILED;
1069    }
1070
1071    switch (crev) {
1072	case 1:
1073	    switch (func) {
1074		case ATOM_LVDS_SUPPORTED_REFRESH_RATE:
1075		    *val = le16_to_cpu(atomDataPtr->LVDS_Info
1076				       .LVDS_Info->usSupportedRefreshRate);
1077		    break;
1078		case ATOM_LVDS_OFF_DELAY:
1079		    *val = le16_to_cpu(atomDataPtr->LVDS_Info
1080				       .LVDS_Info->usOffDelayInMs);
1081		    break;
1082		case ATOM_LVDS_SEQ_DIG_ONTO_DE:
1083		    *val = atomDataPtr->LVDS_Info
1084			.LVDS_Info->ucPowerSequenceDigOntoDEin10Ms * 10;
1085		    break;
1086		case ATOM_LVDS_SEQ_DE_TO_BL:
1087		    *val = atomDataPtr->LVDS_Info
1088			.LVDS_Info->ucPowerSequenceDEtoBLOnin10Ms * 10;
1089		    break;
1090		case     ATOM_LVDS_DITHER:
1091		    *val = atomDataPtr->LVDS_Info
1092			.LVDS_Info->ucLVDS_Misc & 0x40;
1093		    break;
1094		case     ATOM_LVDS_DUALLINK:
1095		    *val = atomDataPtr->LVDS_Info
1096			.LVDS_Info->ucLVDS_Misc & 0x01;
1097		    break;
1098		case     ATOM_LVDS_24BIT:
1099		    *val = atomDataPtr->LVDS_Info
1100			.LVDS_Info->ucLVDS_Misc & 0x02;
1101		    break;
1102		case     ATOM_LVDS_GREYLVL:
1103		    *val = atomDataPtr->LVDS_Info
1104			.LVDS_Info->ucLVDS_Misc & 0x0C;
1105		    break;
1106		case     ATOM_LVDS_FPDI:
1107		    *val = atomDataPtr->LVDS_Info
1108			.LVDS_Info->ucLVDS_Misc * 0x10;
1109		    break;
1110		default:
1111		    return ATOM_NOT_IMPLEMENTED;
1112	    }
1113	    break;
1114	case 2:
1115	    switch (func) {
1116		case ATOM_LVDS_SUPPORTED_REFRESH_RATE:
1117		    *val = le16_to_cpu(atomDataPtr->LVDS_Info
1118				       .LVDS_Info_v12->usSupportedRefreshRate);
1119		    break;
1120		case ATOM_LVDS_OFF_DELAY:
1121		    *val = le16_to_cpu(atomDataPtr->LVDS_Info
1122				       .LVDS_Info_v12->usOffDelayInMs);
1123		    break;
1124		case ATOM_LVDS_SEQ_DIG_ONTO_DE:
1125		    *val = atomDataPtr->LVDS_Info
1126			.LVDS_Info_v12->ucPowerSequenceDigOntoDEin10Ms * 10;
1127		    break;
1128		case ATOM_LVDS_SEQ_DE_TO_BL:
1129		    *val = atomDataPtr->LVDS_Info
1130			.LVDS_Info_v12->ucPowerSequenceDEtoBLOnin10Ms * 10;
1131		    break;
1132		case     ATOM_LVDS_DITHER:
1133		    *val = atomDataPtr->LVDS_Info
1134			.LVDS_Info_v12->ucLVDS_Misc & 0x40;
1135		    break;
1136		case     ATOM_LVDS_DUALLINK:
1137		    *val = atomDataPtr->LVDS_Info
1138			.LVDS_Info_v12->ucLVDS_Misc & 0x01;
1139		    break;
1140		case     ATOM_LVDS_24BIT:
1141		    *val = atomDataPtr->LVDS_Info
1142			.LVDS_Info_v12->ucLVDS_Misc & 0x02;
1143		    break;
1144		case     ATOM_LVDS_GREYLVL:
1145		    *val = atomDataPtr->LVDS_Info
1146			.LVDS_Info_v12->ucLVDS_Misc & 0x0C;
1147		    break;
1148		case     ATOM_LVDS_FPDI:
1149		    *val = atomDataPtr->LVDS_Info
1150			.LVDS_Info_v12->ucLVDS_Misc * 0x10;
1151		    break;
1152		default:
1153		    return ATOM_NOT_IMPLEMENTED;
1154	    }
1155	    break;
1156	default:
1157	    return ATOM_NOT_IMPLEMENTED;
1158    }
1159
1160    return ATOM_SUCCESS;
1161}
1162
1163static AtomBiosResult
1164rhdAtomCompassionateDataQuery(atomBiosHandlePtr handle,
1165			AtomBiosRequestID func, AtomBiosArgPtr data)
1166{
1167    atomDataTablesPtr atomDataPtr;
1168    uint8_t crev, frev;
1169    uint32_t *val = &data->val;
1170
1171    //RHDFUNC(handle);
1172
1173    atomDataPtr = handle->atomDataPtr;
1174
1175    if (!rhdAtomGetTableRevisionAndSize(
1176	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->CompassionateData),
1177	    &frev,&crev,NULL)) {
1178	return ATOM_FAILED;
1179    }
1180
1181    switch (func) {
1182	case ATOM_DAC1_BG_ADJ:
1183	    *val = atomDataPtr->CompassionateData->
1184		ucDAC1_BG_Adjustment;
1185	    break;
1186	case ATOM_DAC1_DAC_ADJ:
1187	    *val = atomDataPtr->CompassionateData->
1188		ucDAC1_DAC_Adjustment;
1189	    break;
1190	case ATOM_DAC1_FORCE:
1191	    *val = atomDataPtr->CompassionateData->
1192		usDAC1_FORCE_Data;
1193	    break;
1194	case ATOM_DAC2_CRTC2_BG_ADJ:
1195	    *val = atomDataPtr->CompassionateData->
1196		ucDAC2_CRT2_BG_Adjustment;
1197	    break;
1198	case ATOM_DAC2_CRTC2_DAC_ADJ:
1199	    *val = atomDataPtr->CompassionateData->
1200		ucDAC2_CRT2_DAC_Adjustment;
1201	    break;
1202	case ATOM_DAC2_CRTC2_FORCE:
1203	    *val = atomDataPtr->CompassionateData->
1204		usDAC2_CRT2_FORCE_Data;
1205	    break;
1206	case ATOM_DAC2_CRTC2_MUX_REG_IND:
1207	    *val = atomDataPtr->CompassionateData->
1208		usDAC2_CRT2_MUX_RegisterIndex;
1209	    break;
1210	case ATOM_DAC2_CRTC2_MUX_REG_INFO:
1211	    *val = atomDataPtr->CompassionateData->
1212		ucDAC2_CRT2_MUX_RegisterInfo;
1213	    break;
1214	default:
1215	    return ATOM_NOT_IMPLEMENTED;
1216    }
1217    return ATOM_SUCCESS;
1218}
1219
1220static AtomBiosResult
1221rhdAtomGPIOI2CInfoQuery(atomBiosHandlePtr handle,
1222			AtomBiosRequestID func, AtomBiosArgPtr data)
1223{
1224    atomDataTablesPtr atomDataPtr;
1225    uint8_t crev, frev;
1226    uint32_t *val = &data->val;
1227    unsigned short size;
1228
1229    //RHDFUNC(handle);
1230
1231    atomDataPtr = handle->atomDataPtr;
1232
1233    if (!rhdAtomGetTableRevisionAndSize(
1234	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->GPIO_I2C_Info),
1235	    &frev,&crev,&size)) {
1236	return ATOM_FAILED;
1237    }
1238
1239    switch (func) {
1240	case ATOM_GPIO_I2C_CLK_MASK:
1241	    if ((sizeof(ATOM_COMMON_TABLE_HEADER)
1242		 + (*val * sizeof(ATOM_GPIO_I2C_ASSIGMENT))) > size) {
1243		xf86DrvMsg(handle->pScrn->scrnIndex, X_ERROR, "%s: GPIO_I2C Device "
1244			   "num %lu exeeds table size %u\n",__func__,
1245			   (unsigned long)val,
1246			   size);
1247		return ATOM_FAILED;
1248	    }
1249
1250	    *val = le16_to_cpu(atomDataPtr->GPIO_I2C_Info->asGPIO_Info[*val]
1251			       .usClkMaskRegisterIndex);
1252	    break;
1253
1254	default:
1255	    return ATOM_NOT_IMPLEMENTED;
1256    }
1257    return ATOM_SUCCESS;
1258}
1259
1260static AtomBiosResult
1261rhdAtomFirmwareInfoQuery(atomBiosHandlePtr handle,
1262			 AtomBiosRequestID func, AtomBiosArgPtr data)
1263{
1264    atomDataTablesPtr atomDataPtr;
1265    uint8_t crev, frev;
1266    uint32_t *val = &data->val;
1267
1268    //RHDFUNC(handle);
1269
1270    atomDataPtr = handle->atomDataPtr;
1271
1272    if (!rhdAtomGetTableRevisionAndSize(
1273	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->FirmwareInfo.base),
1274	    &crev,&frev,NULL)) {
1275	return ATOM_FAILED;
1276    }
1277
1278    switch (crev) {
1279	case 1:
1280	    switch (func) {
1281		case GET_DEFAULT_ENGINE_CLOCK:
1282		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1283				       .FirmwareInfo->ulDefaultEngineClock) * 10;
1284		    break;
1285		case GET_DEFAULT_MEMORY_CLOCK:
1286		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1287				       .FirmwareInfo->ulDefaultMemoryClock) * 10;
1288		    break;
1289		case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
1290		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1291				       .FirmwareInfo->ulMaxPixelClockPLL_Output) * 10;
1292		    break;
1293		case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
1294		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1295				       .FirmwareInfo->usMinPixelClockPLL_Output) * 10;
1296		case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
1297		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1298				       .FirmwareInfo->usMaxPixelClockPLL_Input) * 10;
1299		    break;
1300		case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
1301		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1302				       .FirmwareInfo->usMinPixelClockPLL_Input) * 10;
1303		    break;
1304		case GET_MAX_PIXEL_CLK:
1305		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1306				       .FirmwareInfo->usMaxPixelClock) * 10;
1307		    break;
1308		case GET_REF_CLOCK:
1309		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1310				       .FirmwareInfo->usReferenceClock) * 10;
1311		    break;
1312		default:
1313		    return ATOM_NOT_IMPLEMENTED;
1314	    }
1315	case 2:
1316	    switch (func) {
1317		case GET_DEFAULT_ENGINE_CLOCK:
1318		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1319				       .FirmwareInfo_V_1_2->ulDefaultEngineClock) * 10;
1320		    break;
1321		case GET_DEFAULT_MEMORY_CLOCK:
1322		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1323				       .FirmwareInfo_V_1_2->ulDefaultMemoryClock) * 10;
1324		    break;
1325		case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
1326		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1327				       .FirmwareInfo_V_1_2->ulMaxPixelClockPLL_Output) * 10;
1328		    break;
1329		case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
1330		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1331				       .FirmwareInfo_V_1_2->usMinPixelClockPLL_Output) * 10;
1332		    break;
1333		case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
1334		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1335				       .FirmwareInfo_V_1_2->usMaxPixelClockPLL_Input) * 10;
1336		    break;
1337		case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
1338		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1339				       .FirmwareInfo_V_1_2->usMinPixelClockPLL_Input) * 10;
1340		    break;
1341		case GET_MAX_PIXEL_CLK:
1342		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1343				       .FirmwareInfo_V_1_2->usMaxPixelClock) * 10;
1344		    break;
1345		case GET_REF_CLOCK:
1346		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1347				       .FirmwareInfo_V_1_2->usReferenceClock) * 10;
1348		    break;
1349		default:
1350		    return ATOM_NOT_IMPLEMENTED;
1351	    }
1352	    break;
1353	case 3:
1354	    switch (func) {
1355		case GET_DEFAULT_ENGINE_CLOCK:
1356		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1357				       .FirmwareInfo_V_1_3->ulDefaultEngineClock) * 10;
1358		    break;
1359		case GET_DEFAULT_MEMORY_CLOCK:
1360		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1361				       .FirmwareInfo_V_1_3->ulDefaultMemoryClock) * 10;
1362		    break;
1363		case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
1364		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1365				       .FirmwareInfo_V_1_3->ulMaxPixelClockPLL_Output) * 10;
1366		    break;
1367		case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
1368		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1369				       .FirmwareInfo_V_1_3->usMinPixelClockPLL_Output) * 10;
1370		    break;
1371		case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
1372		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1373				       .FirmwareInfo_V_1_3->usMaxPixelClockPLL_Input) * 10;
1374		    break;
1375		case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
1376		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1377				       .FirmwareInfo_V_1_3->usMinPixelClockPLL_Input) * 10;
1378		    break;
1379		case GET_MAX_PIXEL_CLK:
1380		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1381				       .FirmwareInfo_V_1_3->usMaxPixelClock) * 10;
1382		    break;
1383		case GET_REF_CLOCK:
1384		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1385				       .FirmwareInfo_V_1_3->usReferenceClock) * 10;
1386		    break;
1387		default:
1388		    return ATOM_NOT_IMPLEMENTED;
1389	    }
1390	    break;
1391	case 4:
1392	    switch (func) {
1393		case GET_DEFAULT_ENGINE_CLOCK:
1394		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1395				       .FirmwareInfo_V_1_4->ulDefaultEngineClock) * 10;
1396		    break;
1397		case GET_DEFAULT_MEMORY_CLOCK:
1398		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1399				       .FirmwareInfo_V_1_4->ulDefaultMemoryClock) * 10;
1400		    break;
1401		case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
1402		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1403				       .FirmwareInfo_V_1_4->usMaxPixelClockPLL_Input) * 10;
1404		    break;
1405		case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
1406		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1407				       .FirmwareInfo_V_1_4->usMinPixelClockPLL_Input) * 10;
1408		    break;
1409		case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
1410		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1411				       .FirmwareInfo_V_1_4->ulMaxPixelClockPLL_Output) * 10;
1412		    break;
1413		case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
1414		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1415				       .FirmwareInfo_V_1_4->usMinPixelClockPLL_Output) * 10;
1416		    break;
1417		case GET_MAX_PIXEL_CLK:
1418		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1419				       .FirmwareInfo_V_1_4->usMaxPixelClock) * 10;
1420		    break;
1421		case GET_REF_CLOCK:
1422		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1423				       .FirmwareInfo_V_1_4->usReferenceClock) * 10;
1424		    break;
1425		default:
1426		    return ATOM_NOT_IMPLEMENTED;
1427	    }
1428	    break;
1429	default:
1430	    return ATOM_NOT_IMPLEMENTED;
1431    }
1432    return ATOM_SUCCESS;
1433}
1434
1435const int object_connector_convert[] =
1436    { CONNECTOR_NONE,
1437      CONNECTOR_DVI_I,
1438      CONNECTOR_DVI_I,
1439      CONNECTOR_DVI_D,
1440      CONNECTOR_DVI_D,
1441      CONNECTOR_VGA,
1442      CONNECTOR_CTV,
1443      CONNECTOR_STV,
1444      CONNECTOR_NONE,
1445      CONNECTOR_NONE,
1446      CONNECTOR_DIN,
1447      CONNECTOR_SCART,
1448      CONNECTOR_HDMI_TYPE_A,
1449      CONNECTOR_HDMI_TYPE_B,
1450      CONNECTOR_LVDS,
1451      CONNECTOR_DIN,
1452      CONNECTOR_NONE,
1453      CONNECTOR_NONE,
1454      CONNECTOR_NONE,
1455      CONNECTOR_DISPLAY_PORT,
1456      CONNECTOR_EDP,
1457      CONNECTOR_NONE,
1458    };
1459
1460xf86MonPtr radeon_atom_get_edid(xf86OutputPtr output)
1461{
1462    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1463    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1464    READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION edid_data;
1465    AtomBiosArgRec data;
1466    unsigned char *space;
1467    int i2c_clock = 50;
1468    int engine_clk = (int)info->sclk * 100;
1469    int prescale;
1470    unsigned char *edid;
1471    xf86MonPtr mon = NULL;
1472
1473    if (!radeon_output->ddc_i2c.hw_capable)
1474	return mon;
1475
1476    if (info->atomBIOS->fbBase)
1477	edid = (unsigned char *)info->FB + info->atomBIOS->fbBase;
1478    else if (info->atomBIOS->scratchBase)
1479	edid = (unsigned char *)info->atomBIOS->scratchBase;
1480    else
1481	return mon;
1482
1483    memset(edid, 0, ATOM_EDID_RAW_DATASIZE);
1484
1485    if (info->ChipFamily == CHIP_FAMILY_R520)
1486	prescale = (127 << 8) + (engine_clk * 10) / (4 * 127 * i2c_clock);
1487    else if (info->ChipFamily < CHIP_FAMILY_R600)
1488	prescale = (((engine_clk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
1489    else
1490	prescale = (info->pll.reference_freq * 10) / i2c_clock;
1491
1492    edid_data.usPrescale = prescale;
1493    edid_data.usVRAMAddress = 0;
1494    edid_data.ucSlaveAddr = 0xa0;
1495    edid_data.ucLineNumber = radeon_output->ddc_i2c.hw_line;
1496
1497    data.exec.index = GetIndexIntoMasterTable(COMMAND, ReadEDIDFromHWAssistedI2C);
1498    data.exec.dataSpace = (void *)&space;
1499    data.exec.pspace = &edid_data;
1500
1501    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS)
1502	ErrorF("Atom Get EDID success\n");
1503    else
1504	ErrorF("Atom Get EDID failed\n");
1505
1506    if (edid[1] == 0xff)
1507	mon = xf86InterpretEDID(output->scrn->scrnIndex, edid);
1508
1509    return mon;
1510
1511}
1512
1513static RADEONI2CBusRec
1514RADEONLookupGPIOLineForDDC(ScrnInfoPtr pScrn, uint8_t id)
1515{
1516    RADEONInfoPtr info = RADEONPTR (pScrn);
1517    atomDataTablesPtr atomDataPtr;
1518    ATOM_GPIO_I2C_ASSIGMENT *gpio;
1519    RADEONI2CBusRec i2c;
1520    uint8_t crev, frev;
1521    unsigned short size;
1522    int i, num_indices;
1523
1524    memset(&i2c, 0, sizeof(RADEONI2CBusRec));
1525    i2c.valid = FALSE;
1526
1527    atomDataPtr = info->atomBIOS->atomDataPtr;
1528
1529    if (!rhdAtomGetTableRevisionAndSize(
1530	    &(atomDataPtr->GPIO_I2C_Info->sHeader),
1531	    &crev,&frev,&size)) {
1532	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No GPIO Info Table found!\n");
1533	return i2c;
1534    }
1535
1536    num_indices = size / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
1537
1538    for (i = 0; i < num_indices; i++) {
1539	    gpio = &atomDataPtr->GPIO_I2C_Info->asGPIO_Info[i];
1540
1541	    if (IS_DCE4_VARIANT) {
1542	        if ((i == 7) &&
1543		    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) &&
1544		    (gpio->sucI2cId.ucAccess == 0)) {
1545		    gpio->sucI2cId.ucAccess = 0x97;
1546		    gpio->ucDataMaskShift = 8;
1547		    gpio->ucDataEnShift = 8;
1548		    gpio->ucDataY_Shift = 8;
1549		    gpio->ucDataA_Shift = 8;
1550		}
1551	    }
1552
1553	    if (gpio->sucI2cId.ucAccess == id) {
1554		    i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
1555		    i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
1556		    i2c.put_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
1557		    i2c.put_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
1558		    i2c.get_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
1559		    i2c.get_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
1560		    i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
1561		    i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
1562		    i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
1563		    i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
1564		    i2c.put_clk_mask = (1 << gpio->ucClkEnShift);
1565		    i2c.put_data_mask = (1 << gpio->ucDataEnShift);
1566		    i2c.get_clk_mask = (1 << gpio->ucClkY_Shift);
1567		    i2c.get_data_mask = (1 <<  gpio->ucDataY_Shift);
1568		    i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
1569		    i2c.a_data_mask = (1 <<  gpio->ucDataA_Shift);
1570		    i2c.hw_line = gpio->sucI2cId.ucAccess;
1571		    i2c.hw_capable = gpio->sucI2cId.sbfAccess.bfHW_Capable;
1572		    i2c.valid = TRUE;
1573		    break;
1574	    }
1575    }
1576
1577#if 0
1578    ErrorF("id: %d\n", id);
1579    ErrorF("hw capable: %d\n", gpio->sucI2cId.sbfAccess.bfHW_Capable);
1580    ErrorF("hw engine id: %d\n", gpio->sucI2cId.sbfAccess.bfHW_EngineID);
1581    ErrorF("line mux %d\n", gpio->sucI2cId.sbfAccess.bfI2C_LineMux);
1582    ErrorF("mask_clk_reg: 0x%x\n", le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4);
1583    ErrorF("mask_data_reg: 0x%x\n", le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4);
1584    ErrorF("put_clk_reg: 0x%x\n", le16_to_cpu(gpio->usClkEnRegisterIndex) * 4);
1585    ErrorF("put_data_reg: 0x%x\n", le16_to_cpu(gpio->usDataEnRegisterIndex) * 4);
1586    ErrorF("get_clk_reg: 0x%x\n", le16_to_cpu(gpio->usClkY_RegisterIndex) * 4);
1587    ErrorF("get_data_reg: 0x%x\n", le16_to_cpu(gpio->usDataY_RegisterIndex) * 4);
1588    ErrorF("a_clk_reg: 0x%x\n", le16_to_cpu(gpio->usClkA_RegisterIndex) * 4);
1589    ErrorF("a_data_reg: 0x%x\n", le16_to_cpu(gpio->usDataA_RegisterIndex) * 4);
1590    ErrorF("mask_clk_mask: %d\n", gpio->ucClkMaskShift);
1591    ErrorF("mask_data_mask: %d\n", gpio->ucDataMaskShift);
1592    ErrorF("put_clk_mask: %d\n", gpio->ucClkEnShift);
1593    ErrorF("put_data_mask: %d\n", gpio->ucDataEnShift);
1594    ErrorF("get_clk_mask: %d\n", gpio->ucClkY_Shift);
1595    ErrorF("get_data_mask: %d\n", gpio->ucDataY_Shift);
1596    ErrorF("a_clk_mask: %d\n", gpio->ucClkA_Shift);
1597    ErrorF("a_data_mask: %d\n", gpio->ucDataA_Shift);
1598#endif
1599
1600    return i2c;
1601}
1602
1603static RADEONI2CBusRec
1604rhdAtomParseI2CRecord(ScrnInfoPtr pScrn, atomBiosHandlePtr handle,
1605		      ATOM_I2C_RECORD *Record, int i)
1606{
1607    RADEONInfoPtr info = RADEONPTR (pScrn);
1608    uint8_t *temp = (uint8_t *)&Record->sucI2cId;
1609
1610    info->BiosConnector[i].i2c_line_mux = *temp;
1611    info->BiosConnector[i].ucI2cId = *temp;
1612    return RADEONLookupGPIOLineForDDC(pScrn, *temp);
1613}
1614
1615static uint8_t
1616radeon_lookup_hpd_id(ScrnInfoPtr pScrn, ATOM_HPD_INT_RECORD *record)
1617{
1618    RADEONInfoPtr info = RADEONPTR (pScrn);
1619    unsigned short size;
1620    uint8_t hpd = 0;
1621    int i, num_indices;
1622    struct _ATOM_GPIO_PIN_LUT *gpio_info;
1623    ATOM_GPIO_PIN_ASSIGNMENT *pin;
1624    atomDataTablesPtr atomDataPtr;
1625    uint8_t crev, frev;
1626    uint32_t reg;
1627
1628    atomDataPtr = info->atomBIOS->atomDataPtr;
1629
1630    if (!rhdAtomGetTableRevisionAndSize(
1631	    &(atomDataPtr->GPIO_Pin_LUT->sHeader),
1632	    &crev,&frev,&size)) {
1633	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No GPIO Pin Table found!\n");
1634	return hpd;
1635    }
1636
1637    num_indices = size / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
1638
1639    if (IS_DCE4_VARIANT)
1640	reg = EVERGREEN_DC_GPIO_HPD_A;
1641    else
1642	reg = AVIVO_DC_GPIO_HPD_A;
1643
1644    gpio_info = atomDataPtr->GPIO_Pin_LUT;
1645    for (i = 0; i < num_indices; i++) {
1646	pin = &gpio_info->asGPIO_Pin[i];
1647	if (record->ucHPDIntGPIOID == pin->ucGPIO_ID) {
1648	    if ((le16_to_cpu(pin->usGpioPin_AIndex) * 4) == reg) {
1649		switch (pin->ucGpioPinBitShift) {
1650		case 0:
1651		default:
1652		    hpd = 0;
1653		    break;
1654		case 8:
1655		    hpd = 1;
1656		    break;
1657		case 16:
1658		    hpd = 2;
1659		    break;
1660		case 24:
1661		    hpd = 3;
1662		    break;
1663		case 26:
1664		    hpd = 4;
1665		    break;
1666		case 28:
1667		    hpd = 5;
1668		    break;
1669		}
1670		break;
1671	    }
1672	}
1673    }
1674
1675    return hpd;
1676}
1677
1678static void RADEONApplyATOMQuirks(ScrnInfoPtr pScrn, int index)
1679{
1680    RADEONInfoPtr info = RADEONPTR (pScrn);
1681
1682    /* Asus M2A-VM HDMI board lists the DVI port as HDMI */
1683    if ((info->Chipset == PCI_CHIP_RS690_791E) &&
1684	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1685	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x826d)) {
1686	if ((info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) &&
1687	    (info->BiosConnector[index].devices & ATOM_DEVICE_DFP3_SUPPORT)) {
1688	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D;
1689	}
1690    }
1691
1692    /* RS600 board lists the DVI port as HDMI */
1693    if ((info->Chipset == PCI_CHIP_RS600_7941) &&
1694	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1849) &&
1695	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x7941)) {
1696	if ((info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) &&
1697	    (info->BiosConnector[index].devices & ATOM_DEVICE_DFP3_SUPPORT)) {
1698	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D;
1699	}
1700    }
1701
1702    /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
1703    if ((info->Chipset == PCI_CHIP_RS600_7941) &&
1704	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x147b) &&
1705	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x2412)) {
1706	if (info->BiosConnector[index].ConnectorType == CONNECTOR_DVI_I)
1707	    info->BiosConnector[index].valid = FALSE;
1708    }
1709
1710    /* Falcon NW laptop lists vga ddc line for LVDS */
1711    if ((info->Chipset == PCI_CHIP_RV410_5653) &&
1712	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1462) &&
1713	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0291)) {
1714	if (info->BiosConnector[index].ConnectorType == CONNECTOR_LVDS) {
1715	    info->BiosConnector[index].ddc_i2c.valid = FALSE;
1716	}
1717    }
1718
1719    /* Funky macbooks */
1720    if ((info->Chipset == PCI_CHIP_RV530_71C5) &&
1721	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) &&
1722	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) {
1723	if ((index == ATOM_DEVICE_CRT1_INDEX) ||
1724	    (index == ATOM_DEVICE_CRT2_INDEX) ||
1725	    (index == ATOM_DEVICE_DFP2_INDEX))
1726	    info->BiosConnector[index].valid = FALSE;
1727
1728	if (index == ATOM_DEVICE_DFP1_INDEX) {
1729	    info->BiosConnector[index].devices |= ATOM_DEVICE_CRT2_SUPPORT;
1730	}
1731    }
1732
1733    /* ASUS HD 3600 XT board lists the DVI port as HDMI */
1734    if ((info->Chipset == PCI_CHIP_RV635_9598) &&
1735	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1736	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01da)) {
1737	if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A)
1738	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_I;
1739    }
1740
1741    /* ASUS HD 3450 board lists the DVI port as HDMI */
1742    if ((info->Chipset == PCI_CHIP_RV620_95C5) &&
1743	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1744	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01e2)) {
1745	if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A)
1746	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_I;
1747    }
1748
1749    /* some BIOSes seem to report DAC on HDMI - usually this is a board with
1750     * HDMI + VGA reporting as HDMI
1751     */
1752    if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) {
1753	if (info->BiosConnector[index].devices & (ATOM_DEVICE_CRT_SUPPORT)) {
1754	    info->BiosConnector[index].devices &= ~(ATOM_DEVICE_DFP_SUPPORT);
1755	    info->BiosConnector[index].ConnectorType = CONNECTOR_VGA;
1756	    info->BiosConnector[index].connector_object = 0;
1757	}
1758    }
1759
1760}
1761
1762uint32_t
1763radeon_get_device_index(uint32_t device_support)
1764{
1765    uint32_t device_index = 0;
1766
1767    if (device_support == 0)
1768	return 0;
1769
1770    while ((device_support & 1) == 0) {
1771	device_support >>= 1;
1772	device_index++;
1773    }
1774    return device_index;
1775}
1776
1777radeon_encoder_ptr
1778radeon_get_encoder(xf86OutputPtr output)
1779{
1780    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1781    RADEONInfoPtr info = RADEONPTR(output->scrn);
1782
1783    if (radeon_output->active_device)
1784	return info->encoders[radeon_get_device_index(radeon_output->active_device)];
1785    else
1786	return NULL;
1787}
1788
1789Bool
1790radeon_add_encoder(ScrnInfoPtr pScrn, uint32_t encoder_id, uint32_t device_support)
1791{
1792    RADEONInfoPtr info = RADEONPTR (pScrn);
1793    uint32_t device_index = radeon_get_device_index(device_support);
1794    int i;
1795
1796    if (device_support == 0) {
1797	ErrorF("device support == 0\n");
1798	return FALSE;
1799    }
1800
1801    if (info->encoders[device_index] != NULL)
1802	return TRUE;
1803    else {
1804	/* look for the encoder */
1805	for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
1806	    if ((info->encoders[i] != NULL) && (info->encoders[i]->encoder_id == encoder_id)) {
1807		info->encoders[device_index] = info->encoders[i];
1808		switch (encoder_id) {
1809		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1810		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1811		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1812		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1813		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1814		    if (device_support & ATOM_DEVICE_LCD1_SUPPORT) {
1815			if (info->encoders[device_index]->dev_priv == NULL) {
1816			    info->encoders[device_index]->dev_priv =
1817				(radeon_lvds_ptr)calloc(1,sizeof(radeon_lvds_rec));
1818			    if (info->encoders[device_index]->dev_priv == NULL) {
1819				ErrorF("calloc failed\n");
1820				return FALSE;
1821			    } else
1822				RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1823			}
1824		    }
1825		    break;
1826		}
1827		return TRUE;
1828	    }
1829	}
1830
1831	info->encoders[device_index] = (radeon_encoder_ptr)calloc(1,sizeof(radeon_encoder_rec));
1832	if (info->encoders[device_index] != NULL) {
1833	    info->encoders[device_index]->encoder_id = encoder_id;
1834	    info->encoders[device_index]->devices = 0;
1835	    info->encoders[device_index]->dev_priv = NULL;
1836	    // add dev_priv stuff
1837	    switch (encoder_id) {
1838	    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1839		    info->encoders[device_index]->dev_priv = (radeon_lvds_ptr)calloc(1,sizeof(radeon_lvds_rec));
1840		    if (info->encoders[device_index]->dev_priv == NULL) {
1841			ErrorF("calloc failed\n");
1842			return FALSE;
1843		    } else {
1844			if (info->IsAtomBios)
1845			    RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1846			else
1847			    RADEONGetLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1848		    }
1849		break;
1850	    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1851		if (!IS_AVIVO_VARIANT) {
1852		    info->encoders[device_index]->dev_priv = (radeon_tvdac_ptr)calloc(1,sizeof(radeon_tvdac_rec));
1853		    if (info->encoders[device_index]->dev_priv == NULL) {
1854			ErrorF("calloc failed\n");
1855			return FALSE;
1856		    } else
1857			RADEONGetTVDacAdjInfo(pScrn, (radeon_tvdac_ptr)info->encoders[device_index]->dev_priv);
1858		}
1859		break;
1860	    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1861		if (!IS_AVIVO_VARIANT) {
1862		    info->encoders[device_index]->dev_priv = (radeon_tmds_ptr)calloc(1,sizeof(radeon_tmds_rec));
1863		    if (info->encoders[device_index]->dev_priv == NULL) {
1864			ErrorF("calloc failed\n");
1865			return FALSE;
1866		    } else
1867			RADEONGetTMDSInfo(pScrn, (radeon_tmds_ptr)info->encoders[device_index]->dev_priv);
1868		}
1869		break;
1870	    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1871		if (!IS_AVIVO_VARIANT) {
1872		    info->encoders[device_index]->dev_priv = (radeon_dvo_ptr)calloc(1,sizeof(radeon_dvo_rec));
1873		    if (info->encoders[device_index]->dev_priv == NULL) {
1874			ErrorF("calloc failed\n");
1875			return FALSE;
1876		    } else
1877			RADEONGetExtTMDSInfo(pScrn, (radeon_dvo_ptr)info->encoders[device_index]->dev_priv);
1878		}
1879		break;
1880	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1881	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1882	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1883	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1884	    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1885		if (device_support & ATOM_DEVICE_LCD1_SUPPORT) {
1886		    info->encoders[device_index]->dev_priv = (radeon_lvds_ptr)calloc(1,sizeof(radeon_lvds_rec));
1887		    if (info->encoders[device_index]->dev_priv == NULL) {
1888			ErrorF("calloc failed\n");
1889			return FALSE;
1890		    } else
1891			RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1892		}
1893		break;
1894	    }
1895	    return TRUE;
1896	} else {
1897	    ErrorF("calloc failed\n");
1898	    return FALSE;
1899	}
1900    }
1901
1902}
1903
1904Bool
1905RADEONGetATOMConnectorInfoFromBIOSObject (ScrnInfoPtr pScrn)
1906{
1907    RADEONInfoPtr info = RADEONPTR (pScrn);
1908    uint8_t crev, frev;
1909    unsigned short size;
1910    atomDataTablesPtr atomDataPtr;
1911    ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
1912    ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
1913    ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj = NULL;
1914    int i, j, path_size, device_support;
1915    Bool enable_tv = FALSE;
1916
1917    if (xf86ReturnOptValBool(info->Options, OPTION_ATOM_TVOUT, FALSE))
1918	enable_tv = TRUE;
1919
1920    atomDataPtr = info->atomBIOS->atomDataPtr;
1921    if (!rhdAtomGetTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->Object_Header), &crev, &frev, &size))
1922	return FALSE;
1923
1924    if (crev < 2)
1925	return FALSE;
1926
1927    path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
1928	((char *)&atomDataPtr->Object_Header->sHeader +
1929	 le16_to_cpu(atomDataPtr->Object_Header->usDisplayPathTableOffset));
1930    con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
1931	((char *)&atomDataPtr->Object_Header->sHeader +
1932	 le16_to_cpu(atomDataPtr->Object_Header->usConnectorObjectTableOffset));
1933    device_support = le16_to_cpu(atomDataPtr->Object_Header->usDeviceSupport);
1934
1935    path_size = 0;
1936    for (i = 0; i < path_obj->ucNumOfDispPath; i++) {
1937	uint8_t *addr = (uint8_t *)path_obj->asDispPath;
1938	ATOM_DISPLAY_OBJECT_PATH *path;
1939	addr += path_size;
1940	path = (ATOM_DISPLAY_OBJECT_PATH *)addr;
1941	path_size += le16_to_cpu(path->usSize);
1942
1943	if (device_support & le16_to_cpu(path->usDeviceTag)) {
1944	    uint8_t con_obj_id, con_obj_num, con_obj_type;
1945
1946	    con_obj_id = (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
1947	    con_obj_num = (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
1948	    con_obj_type = (le16_to_cpu(path->usConnObjectId) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
1949
1950	    if ((le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_TV1_SUPPORT) ||
1951		(le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_TV2_SUPPORT)) {
1952		if (!enable_tv) {
1953		    info->BiosConnector[i].valid = FALSE;
1954		    continue;
1955		}
1956	    }
1957
1958	    /* don't support CV yet */
1959	    if (le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_CV_SUPPORT) {
1960		info->BiosConnector[i].valid = FALSE;
1961		continue;
1962	    }
1963
1964	    if (info->IsIGP &&
1965		(con_obj_id == CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) {
1966		uint32_t slot_config, ct;
1967
1968		igp_obj = info->atomBIOS->atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2;
1969
1970		if (!igp_obj)
1971		    info->BiosConnector[i].ConnectorType = object_connector_convert[con_obj_id];
1972		else {
1973		    if (con_obj_num == 1)
1974			slot_config = igp_obj->ulDDISlot1Config;
1975		    else
1976			slot_config = igp_obj->ulDDISlot2Config;
1977
1978		    ct = (slot_config  >> 16) & 0xff;
1979		    info->BiosConnector[i].ConnectorType = object_connector_convert[ct];
1980		    info->BiosConnector[i].connector_object_id = ct;
1981		    info->BiosConnector[i].igp_lane_info = slot_config & 0xffff;
1982		}
1983	    } else {
1984		info->BiosConnector[i].ConnectorType = object_connector_convert[con_obj_id];
1985		info->BiosConnector[i].connector_object_id = con_obj_id;
1986	    }
1987
1988	    if (info->BiosConnector[i].ConnectorType == CONNECTOR_NONE) {
1989		info->BiosConnector[i].valid = FALSE;
1990		continue;
1991	    } else
1992		info->BiosConnector[i].valid = TRUE;
1993	    info->BiosConnector[i].devices = le16_to_cpu(path->usDeviceTag);
1994	    info->BiosConnector[i].connector_object = le16_to_cpu(path->usConnObjectId);
1995
1996	    for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
1997		uint8_t enc_obj_id, enc_obj_num, enc_obj_type;
1998
1999		enc_obj_id = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
2000		enc_obj_num = (le16_to_cpu(path->usGraphicObjIds[j]) & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
2001		enc_obj_type = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
2002
2003		if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
2004		    if (enc_obj_num == 2)
2005			info->BiosConnector[i].linkb = TRUE;
2006		    else
2007			info->BiosConnector[i].linkb = FALSE;
2008
2009		    if (!radeon_add_encoder(pScrn, enc_obj_id, le16_to_cpu(path->usDeviceTag)))
2010			return FALSE;
2011		}
2012	    }
2013
2014	    /* look up gpio for ddc */
2015	    if ((le16_to_cpu(path->usDeviceTag) & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
2016		for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
2017		    if (le16_to_cpu(path->usConnObjectId) == le16_to_cpu(con_obj->asObjects[j].usObjectID)) {
2018			ATOM_COMMON_RECORD_HEADER *Record = (ATOM_COMMON_RECORD_HEADER *)
2019			    ((char *)&atomDataPtr->Object_Header->sHeader
2020			     + le16_to_cpu(con_obj->asObjects[j].usRecordOffset));
2021
2022			while (Record->ucRecordType > 0
2023			       && Record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER ) {
2024
2025			    /*ErrorF("record type %d\n", Record->ucRecordType);*/
2026			    switch (Record->ucRecordType) {
2027			    case ATOM_I2C_RECORD_TYPE:
2028				info->BiosConnector[i].ddc_i2c =
2029				    rhdAtomParseI2CRecord(pScrn, info->atomBIOS,
2030							  (ATOM_I2C_RECORD *)Record, j);
2031				break;
2032			    case ATOM_HPD_INT_RECORD_TYPE:
2033				info->BiosConnector[i].hpd_id =
2034				    radeon_lookup_hpd_id(pScrn,
2035							 (ATOM_HPD_INT_RECORD *)Record);
2036				break;
2037			    case ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE:
2038				break;
2039			    }
2040
2041			    Record = (ATOM_COMMON_RECORD_HEADER*)
2042				((char *)Record + Record->ucRecordSize);
2043			}
2044			break;
2045		    }
2046		}
2047	    }
2048	}
2049	RADEONApplyATOMQuirks(pScrn, i);
2050    }
2051
2052    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2053	if (info->BiosConnector[i].valid) {
2054	    /* shared connectors */
2055	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2056		if (info->BiosConnector[j].valid && (i != j) ) {
2057		    if (info->BiosConnector[i].connector_object == info->BiosConnector[j].connector_object) {
2058			info->BiosConnector[i].devices |= info->BiosConnector[j].devices;
2059			info->BiosConnector[j].valid = FALSE;
2060		    }
2061		}
2062	    }
2063	    /* shared ddc */
2064	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2065		if (info->BiosConnector[j].valid && (i != j) ) {
2066		    if (info->BiosConnector[i].i2c_line_mux == info->BiosConnector[j].i2c_line_mux) {
2067			info->BiosConnector[i].shared_ddc = TRUE;
2068			info->BiosConnector[j].shared_ddc = TRUE;
2069		    }
2070		}
2071	    }
2072	}
2073    }
2074
2075    return TRUE;
2076}
2077
2078static void
2079RADEONGetATOMLVDSInfo(ScrnInfoPtr pScrn, radeon_lvds_ptr lvds)
2080{
2081    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2082    radeon_native_mode_ptr native_mode = &lvds->native_mode;
2083    atomDataTablesPtr atomDataPtr;
2084    uint8_t crev, frev;
2085    uint16_t misc;
2086
2087    atomDataPtr = info->atomBIOS->atomDataPtr;
2088
2089    if (!rhdAtomGetTableRevisionAndSize(
2090	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
2091	    &frev,&crev,NULL)) {
2092	return;
2093    }
2094
2095    switch (crev) {
2096    case 1:
2097	native_mode->PanelXRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHActive);
2098	native_mode->PanelYRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVActive);
2099	native_mode->DotClock   = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usPixClk) * 10;
2100	native_mode->HBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHBlanking_Time);
2101	native_mode->HOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHSyncOffset);
2102	native_mode->HSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHSyncWidth);
2103	native_mode->VBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVBlanking_Time);
2104	native_mode->VOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVSyncOffset);
2105	native_mode->VSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVSyncWidth);
2106	misc = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.susModeMiscInfo.usAccess);
2107	if (misc & ATOM_VSYNC_POLARITY)
2108	    native_mode->Flags |= V_NVSYNC;
2109	if (misc & ATOM_HSYNC_POLARITY)
2110	    native_mode->Flags |= V_NHSYNC;
2111	if (misc & ATOM_COMPOSITESYNC)
2112	    native_mode->Flags |= V_CSYNC;
2113	if (misc & ATOM_INTERLACE)
2114	    native_mode->Flags |= V_INTERLACE;
2115	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2116	    native_mode->Flags |= V_DBLSCAN;
2117	lvds->PanelPwrDly = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->usOffDelayInMs);
2118	lvds->lvds_misc   =  atomDataPtr->LVDS_Info.LVDS_Info->ucLVDS_Misc;
2119	lvds->lvds_ss_id  =  atomDataPtr->LVDS_Info.LVDS_Info->ucSS_Id;
2120	break;
2121    case 2:
2122	native_mode->PanelXRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHActive);
2123	native_mode->PanelYRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVActive);
2124	native_mode->DotClock   = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usPixClk) * 10;
2125	native_mode->HBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHBlanking_Time);
2126	native_mode->HOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHSyncOffset);
2127	native_mode->HSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHSyncWidth);
2128	native_mode->VBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVBlanking_Time);
2129	native_mode->VOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVSyncOffset);
2130	native_mode->VSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVSyncWidth);
2131	misc = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.susModeMiscInfo.usAccess);
2132	if (misc & ATOM_VSYNC_POLARITY)
2133	    native_mode->Flags |= V_NVSYNC;
2134	if (misc & ATOM_HSYNC_POLARITY)
2135	    native_mode->Flags |= V_NHSYNC;
2136	if (misc & ATOM_COMPOSITESYNC)
2137	    native_mode->Flags |= V_CSYNC;
2138	if (misc & ATOM_INTERLACE)
2139	    native_mode->Flags |= V_INTERLACE;
2140	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2141	    native_mode->Flags |= V_DBLSCAN;
2142	lvds->PanelPwrDly = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->usOffDelayInMs);
2143	lvds->lvds_misc   =  atomDataPtr->LVDS_Info.LVDS_Info_v12->ucLVDS_Misc;
2144	lvds->lvds_ss_id  =  atomDataPtr->LVDS_Info.LVDS_Info_v12->ucSS_Id;
2145	break;
2146    }
2147    native_mode->Flags = 0;
2148
2149    if (lvds->PanelPwrDly > 2000 || lvds->PanelPwrDly < 0)
2150	lvds->PanelPwrDly = 2000;
2151
2152    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2153	       "LVDS Info:\n"
2154	       "XRes: %d, YRes: %d, DotClock: %d\n"
2155	       "HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n"
2156	       "VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n",
2157	       native_mode->PanelXRes, native_mode->PanelYRes, native_mode->DotClock,
2158	       native_mode->HBlank, native_mode->HOverPlus, native_mode->HSyncWidth,
2159	       native_mode->VBlank, native_mode->VOverPlus, native_mode->VSyncWidth);
2160}
2161
2162void
2163RADEONATOMGetIGPInfo(ScrnInfoPtr pScrn)
2164{
2165    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2166    atomDataTablesPtr atomDataPtr;
2167    unsigned short size;
2168    uint8_t crev, frev;
2169
2170    atomDataPtr = info->atomBIOS->atomDataPtr;
2171
2172    if (!rhdAtomGetTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->IntegratedSystemInfo.base), &frev, &crev, &size))
2173	return;
2174
2175    switch (crev) {
2176    case 1:
2177	info->igp_sideport_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->ulBootUpMemoryClock / 100.0;
2178	info->igp_system_mclk = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usK8MemoryClock);
2179	info->igp_ht_link_clk = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usFSBClock);
2180	info->igp_ht_link_width = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->ucHTLinkWidth;
2181	break;
2182    case 2:
2183	info->igp_sideport_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulBootUpSidePortClock / 100.0;
2184	info->igp_system_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulBootUpUMAClock / 100.0;
2185	info->igp_ht_link_clk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulHTLinkFreq / 100.0;
2186	info->igp_ht_link_width = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->usMinHTLinkWidth);
2187	break;
2188    }
2189}
2190
2191Bool
2192RADEONGetATOMTVInfo(xf86OutputPtr output)
2193{
2194    ScrnInfoPtr pScrn = output->scrn;
2195    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2196    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2197    radeon_tvout_ptr tvout = &radeon_output->tvout;
2198    ATOM_ANALOG_TV_INFO *tv_info;
2199
2200    tv_info = info->atomBIOS->atomDataPtr->AnalogTV_Info.AnalogTV_Info;
2201
2202    if (!tv_info)
2203	return FALSE;
2204
2205    switch(tv_info->ucTV_BootUpDefaultStandard) {
2206    case NTSCJ_SUPPORT:
2207	tvout->default_tvStd = TV_STD_NTSC_J;
2208	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC-J\n");
2209	break;
2210    case PAL_SUPPORT:
2211	tvout->default_tvStd = TV_STD_PAL;
2212	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL\n");
2213	break;
2214    case PALM_SUPPORT:
2215	tvout->default_tvStd = TV_STD_PAL_M;
2216	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-M\n");
2217	break;
2218    case PAL60_SUPPORT:
2219	tvout->default_tvStd = TV_STD_PAL_60;
2220	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-60\n");
2221	break;
2222    default:
2223    case NTSC_SUPPORT:
2224	tvout->default_tvStd = TV_STD_NTSC;
2225	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC\n");
2226	break;
2227    }
2228
2229    tvout->tvStd = tvout->default_tvStd;
2230
2231    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standards supported by chip: ");
2232    tvout->SupportedTVStds = tvout->default_tvStd;
2233    if (tv_info->ucTV_SupportedStandard & NTSC_SUPPORT) {
2234	ErrorF("NTSC ");
2235	tvout->SupportedTVStds |= TV_STD_NTSC;
2236    }
2237    if (tv_info->ucTV_SupportedStandard & NTSCJ_SUPPORT) {
2238	ErrorF("NTSC-J ");
2239	tvout->SupportedTVStds |= TV_STD_NTSC_J;
2240    }
2241    if (tv_info->ucTV_SupportedStandard & PAL_SUPPORT) {
2242	ErrorF("PAL ");
2243	tvout->SupportedTVStds |= TV_STD_PAL;
2244    }
2245    if (tv_info->ucTV_SupportedStandard & PALM_SUPPORT) {
2246	ErrorF("PAL-M ");
2247	tvout->SupportedTVStds |= TV_STD_PAL_M;
2248    }
2249    if (tv_info->ucTV_SupportedStandard & PAL60_SUPPORT) {
2250	ErrorF("PAL-60 ");
2251	tvout->SupportedTVStds |= TV_STD_PAL_60;
2252    }
2253    ErrorF("\n");
2254
2255    if (tv_info->ucExt_TV_ASIC_ID) {
2256	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unknown external TV ASIC\n");
2257	return FALSE;
2258    }
2259
2260    return TRUE;
2261}
2262
2263Bool
2264RADEONGetATOMClockInfo(ScrnInfoPtr pScrn)
2265{
2266    RADEONInfoPtr info = RADEONPTR (pScrn);
2267    RADEONPLLPtr pll = &info->pll;
2268    atomDataTablesPtr atomDataPtr;
2269    uint8_t crev, frev;
2270
2271    atomDataPtr = info->atomBIOS->atomDataPtr;
2272    if (!rhdAtomGetTableRevisionAndSize(
2273	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->FirmwareInfo.base),
2274	    &crev,&frev,NULL)) {
2275	return FALSE;
2276    }
2277
2278    switch(crev) {
2279    case 1:
2280	info->sclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulDefaultEngineClock) / 100.0;
2281	info->mclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulDefaultMemoryClock) / 100.0;
2282	pll->xclk = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMaxPixelClock);
2283	pll->pll_in_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMinPixelClockPLL_Input);
2284	pll->pll_in_max = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMaxPixelClockPLL_Input);
2285	pll->pll_out_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMinPixelClockPLL_Output);
2286	pll->pll_out_max = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulMaxPixelClockPLL_Output);
2287	pll->reference_freq = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usReferenceClock);
2288	break;
2289    case 2:
2290    case 3:
2291    case 4:
2292    default:
2293	info->sclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulDefaultEngineClock) / 100.0;
2294	info->mclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulDefaultMemoryClock) / 100.0;
2295	pll->xclk = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMaxPixelClock);
2296	pll->pll_in_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMinPixelClockPLL_Input);
2297	pll->pll_in_max = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMaxPixelClockPLL_Input);
2298	pll->pll_out_min = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulMinPixelClockPLL_Output);
2299	pll->pll_out_max = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulMaxPixelClockPLL_Output);
2300	pll->reference_freq = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usReferenceClock);
2301	break;
2302    }
2303    pll->reference_div = 0;
2304    if (pll->pll_out_min == 0) {
2305	if (IS_AVIVO_VARIANT)
2306	    pll->pll_out_min = 64800;
2307	else
2308	    pll->pll_out_min = 20000;
2309    }
2310
2311    /* limiting the range is a good thing in most cases
2312     * as it limits the number of matching pll combinations,
2313     * however, some duallink DVI monitors seem to prefer combinations that
2314     * would be limited by this.  This may need to be revisited
2315     * per chip family.
2316     */
2317    if (!xf86ReturnOptValBool(info->Options, OPTION_NEW_PLL, TRUE)) {
2318	if (pll->pll_out_min > 64800)
2319	    pll->pll_out_min = 64800;
2320    }
2321
2322    if (IS_DCE4_VARIANT) {
2323	info->default_dispclk =
2324	    le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_2_1->ulDefaultDispEngineClkFreq);
2325	if (info->default_dispclk == 0)
2326	    info->default_dispclk = 60000;
2327	info->dp_extclk = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_2_1->usUniphyDPModeExtClkFreq);
2328    }
2329    return TRUE;
2330}
2331
2332Bool
2333RADEONATOMGetTVTimings(ScrnInfoPtr pScrn, int index, DisplayModePtr mode)
2334{
2335    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2336    ATOM_ANALOG_TV_INFO *tv_info;
2337    ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2;
2338    ATOM_DTD_FORMAT *dtd_timings;
2339    atomDataTablesPtr atomDataPtr;
2340    uint8_t crev, frev;
2341    uint16_t misc;
2342
2343    atomDataPtr = info->atomBIOS->atomDataPtr;
2344    if (!rhdAtomGetTableRevisionAndSize(
2345	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->AnalogTV_Info.base),
2346	    &crev,&frev,NULL)) {
2347	return FALSE;
2348    }
2349
2350    switch(crev) {
2351    case 1:
2352	tv_info = atomDataPtr->AnalogTV_Info.AnalogTV_Info;
2353
2354	if (index > MAX_SUPPORTED_TV_TIMING)
2355	    return FALSE;
2356
2357	mode->CrtcHTotal     = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
2358	mode->CrtcHDisplay   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
2359	mode->CrtcHSyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
2360	mode->CrtcHSyncEnd   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) +
2361	                       le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
2362
2363	mode->CrtcVTotal     = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
2364	mode->CrtcVDisplay   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
2365	mode->CrtcVSyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
2366	mode->CrtcVSyncEnd   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) +
2367	                       le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
2368
2369	mode->Flags = 0;
2370	misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess);
2371	if (misc & ATOM_VSYNC_POLARITY)
2372	    mode->Flags |= V_NVSYNC;
2373	if (misc & ATOM_HSYNC_POLARITY)
2374	    mode->Flags |= V_NHSYNC;
2375	if (misc & ATOM_COMPOSITESYNC)
2376	    mode->Flags |= V_CSYNC;
2377	if (misc & ATOM_INTERLACE)
2378	    mode->Flags |= V_INTERLACE;
2379	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2380	    mode->Flags |= V_DBLSCAN;
2381
2382	mode->Clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
2383
2384	if (index == 1) {
2385		/* PAL timings appear to have wrong values for totals */
2386		mode->CrtcHTotal -= 1;
2387		mode->CrtcVTotal -= 1;
2388	}
2389	break;
2390    case 2:
2391	tv_info_v1_2 = atomDataPtr->AnalogTV_Info.AnalogTV_Info_v1_2;
2392	if (index > MAX_SUPPORTED_TV_TIMING_V1_2)
2393	    return FALSE;
2394
2395	dtd_timings = &tv_info_v1_2->aModeTimings[index];
2396	mode->CrtcHTotal     = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHBlanking_Time);
2397	mode->CrtcHDisplay   = le16_to_cpu(dtd_timings->usHActive);
2398	mode->CrtcHSyncStart = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHSyncOffset);
2399	mode->CrtcHSyncEnd   = mode->CrtcHSyncStart + le16_to_cpu(dtd_timings->usHSyncWidth);
2400
2401	mode->CrtcVTotal     = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVBlanking_Time);
2402	mode->CrtcVDisplay   = le16_to_cpu(dtd_timings->usVActive);
2403	mode->CrtcVSyncStart = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVSyncOffset);
2404	mode->CrtcVSyncEnd   = mode->CrtcVSyncStart + le16_to_cpu(dtd_timings->usVSyncWidth);
2405
2406	mode->Flags = 0;
2407	misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
2408	if (misc & ATOM_VSYNC_POLARITY)
2409	    mode->Flags |= V_NVSYNC;
2410	if (misc & ATOM_HSYNC_POLARITY)
2411	    mode->Flags |= V_NHSYNC;
2412	if (misc & ATOM_COMPOSITESYNC)
2413	    mode->Flags |= V_CSYNC;
2414	if (misc & ATOM_INTERLACE)
2415	    mode->Flags |= V_INTERLACE;
2416	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2417	    mode->Flags |= V_DBLSCAN;
2418
2419	mode->Clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
2420
2421	break;
2422    }
2423
2424    return TRUE;
2425}
2426
2427uint32_t
2428radeon_get_encoder_id_from_supported_device(ScrnInfoPtr pScrn, uint32_t supported_device, int dac)
2429{
2430    RADEONInfoPtr info = RADEONPTR (pScrn);
2431    uint32_t ret = 0;
2432
2433    switch (supported_device) {
2434    case ATOM_DEVICE_CRT1_SUPPORT:
2435    case ATOM_DEVICE_TV1_SUPPORT:
2436    case ATOM_DEVICE_TV2_SUPPORT:
2437    case ATOM_DEVICE_CRT2_SUPPORT:
2438    case ATOM_DEVICE_CV_SUPPORT:
2439	switch (dac) {
2440	    // primary dac
2441	case 1:
2442	    if ((info->ChipFamily == CHIP_FAMILY_RS300) ||
2443		(info->ChipFamily == CHIP_FAMILY_RS400) ||
2444		(info->ChipFamily == CHIP_FAMILY_RS480))
2445		ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
2446	    else if (IS_AVIVO_VARIANT)
2447		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1;
2448	    else
2449		ret = ENCODER_OBJECT_ID_INTERNAL_DAC1;
2450	    break;
2451	    // secondary dac
2452	case 2:
2453	    if (IS_AVIVO_VARIANT)
2454		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2;
2455	    else {
2456		/*if (info->ChipFamily == CHIP_FAMILY_R200)
2457		    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2458		    else*/
2459		    ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
2460	    }
2461	    break;
2462	    // external dac
2463	case 3:
2464	    if (IS_AVIVO_VARIANT)
2465		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
2466	    else
2467		ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2468	    break;
2469	}
2470	break;
2471    case ATOM_DEVICE_LCD1_SUPPORT:
2472	if (IS_AVIVO_VARIANT)
2473	    ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
2474	else
2475	    ret = ENCODER_OBJECT_ID_INTERNAL_LVDS;
2476	break;
2477    case ATOM_DEVICE_DFP1_SUPPORT:
2478	if ((info->ChipFamily == CHIP_FAMILY_RS300) ||
2479	    (info->ChipFamily == CHIP_FAMILY_RS400) ||
2480	    (info->ChipFamily == CHIP_FAMILY_RS480))
2481	    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2482	else if (IS_AVIVO_VARIANT)
2483	    ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1;
2484	else
2485	    ret = ENCODER_OBJECT_ID_INTERNAL_TMDS1;
2486	break;
2487    case ATOM_DEVICE_LCD2_SUPPORT:
2488    case ATOM_DEVICE_DFP2_SUPPORT:
2489	if ((info->ChipFamily == CHIP_FAMILY_RS600) ||
2490	    (info->ChipFamily == CHIP_FAMILY_RS690) ||
2491	    (info->ChipFamily == CHIP_FAMILY_RS740))
2492	    ret = ENCODER_OBJECT_ID_INTERNAL_DDI;
2493	else if (IS_AVIVO_VARIANT)
2494	    ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
2495	else
2496	    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2497	break;
2498    case ATOM_DEVICE_DFP3_SUPPORT:
2499	ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
2500	break;
2501    }
2502
2503    return ret;
2504}
2505
2506Bool
2507RADEONGetATOMConnectorInfoFromBIOSConnectorTable (ScrnInfoPtr pScrn)
2508{
2509    RADEONInfoPtr info = RADEONPTR (pScrn);
2510    atomDataTablesPtr atomDataPtr;
2511    uint8_t crev, frev;
2512    int i, j;
2513    Bool enable_tv = FALSE;
2514
2515    if (xf86ReturnOptValBool(info->Options, OPTION_ATOM_TVOUT, FALSE))
2516	enable_tv = TRUE;
2517
2518    atomDataPtr = info->atomBIOS->atomDataPtr;
2519
2520    if (!rhdAtomGetTableRevisionAndSize(
2521	    &(atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->sHeader),
2522	    &crev,&frev,NULL)) {
2523	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Device Info Table found!\n");
2524	return FALSE;
2525    }
2526
2527    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2528	ATOM_CONNECTOR_INFO_I2C ci
2529	    = atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->asConnInfo[i];
2530
2531	if (!(le16_to_cpu(atomDataPtr->SupportedDevicesInfo
2532			  .SupportedDevicesInfo->usDeviceSupport) & (1 << i))) {
2533	    info->BiosConnector[i].valid = FALSE;
2534	    continue;
2535	}
2536
2537	/* don't support CV yet */
2538	if (i == ATOM_DEVICE_CV_INDEX) {
2539	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Skipping Component Video\n");
2540	    info->BiosConnector[i].valid = FALSE;
2541	    continue;
2542	}
2543
2544	if (!enable_tv && (i == ATOM_DEVICE_TV1_INDEX)) {
2545	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Skipping TV-Out\n");
2546	    info->BiosConnector[i].valid = FALSE;
2547	    continue;
2548	}
2549
2550	info->BiosConnector[i].valid = TRUE;
2551	info->BiosConnector[i].load_detection = TRUE;
2552	info->BiosConnector[i].shared_ddc = FALSE;
2553	info->BiosConnector[i].output_id = ci.sucI2cId.ucAccess;
2554	info->BiosConnector[i].devices = (1 << i);
2555	info->BiosConnector[i].ConnectorType = ci.sucConnectorInfo.sbfAccess.bfConnectorType;
2556
2557	if (info->BiosConnector[i].ConnectorType == CONNECTOR_NONE) {
2558	    info->BiosConnector[i].valid = FALSE;
2559	    continue;
2560	}
2561
2562	/* don't assign a gpio for tv */
2563	if ((i == ATOM_DEVICE_TV1_INDEX) ||
2564	    (i == ATOM_DEVICE_TV2_INDEX) ||
2565	    (i == ATOM_DEVICE_CV_INDEX))
2566	    info->BiosConnector[i].ddc_i2c.valid = FALSE;
2567	else
2568	    info->BiosConnector[i].ddc_i2c =
2569		RADEONLookupGPIOLineForDDC(pScrn, ci.sucI2cId.ucAccess);
2570
2571	if (!radeon_add_encoder(pScrn,
2572			   radeon_get_encoder_id_from_supported_device(pScrn, (1 << i),
2573					  ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC),
2574				(1 << i)))
2575	    return FALSE;
2576
2577	/* Always set the connector type to VGA for CRT1/CRT2. if they are
2578	 * shared with a DVI port, we'll pick up the DVI connector below when we
2579	 * merge the outputs
2580	 */
2581	if ((i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) &&
2582	    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I ||
2583	     info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D ||
2584	     info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A)) {
2585	    info->BiosConnector[i].ConnectorType = CONNECTOR_VGA;
2586	}
2587
2588	if (crev > 1) {
2589	    ATOM_CONNECTOR_INC_SRC_BITMAP isb
2590		= atomDataPtr->SupportedDevicesInfo
2591		.SupportedDevicesInfo_HD->asIntSrcInfo[i];
2592
2593	    switch (isb.ucIntSrcBitmap) {
2594		case 0x4:
2595		    info->BiosConnector[i].hpd_mask = 0x00000001;
2596		    break;
2597		case 0xa:
2598		    info->BiosConnector[i].hpd_mask = 0x00000100;
2599		    break;
2600		default:
2601		    info->BiosConnector[i].hpd_mask = 0;
2602		    break;
2603	    }
2604	} else
2605	    info->BiosConnector[i].hpd_mask = 0;
2606
2607	RADEONApplyATOMQuirks(pScrn, i);
2608
2609    }
2610
2611    /* CRTs/DFPs may share a port */
2612    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2613	if (info->BiosConnector[i].valid) {
2614	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2615		if (info->BiosConnector[j].valid && (i != j) ) {
2616		    if (info->BiosConnector[i].output_id == info->BiosConnector[j].output_id) {
2617			if (((i == ATOM_DEVICE_DFP1_INDEX) ||
2618			     (i == ATOM_DEVICE_DFP2_INDEX) ||
2619			     (i == ATOM_DEVICE_DFP3_INDEX)) &&
2620			    ((j == ATOM_DEVICE_CRT1_INDEX) ||
2621			     (j == ATOM_DEVICE_CRT2_INDEX))) {
2622			    info->BiosConnector[i].devices |= info->BiosConnector[j].devices;
2623			    if (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D)
2624				info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_I;
2625			    info->BiosConnector[j].valid = FALSE;
2626			} else if (((j == ATOM_DEVICE_DFP1_INDEX) ||
2627				    (j == ATOM_DEVICE_DFP2_INDEX) ||
2628				    (j == ATOM_DEVICE_DFP3_INDEX)) &&
2629				   ((i == ATOM_DEVICE_CRT1_INDEX) ||
2630				    (i == ATOM_DEVICE_CRT2_INDEX))) {
2631			    info->BiosConnector[j].devices |= info->BiosConnector[i].devices;
2632			    if (info->BiosConnector[j].ConnectorType == CONNECTOR_DVI_D)
2633				info->BiosConnector[j].ConnectorType = CONNECTOR_DVI_I;
2634			    info->BiosConnector[i].valid = FALSE;
2635			} else {
2636			    info->BiosConnector[i].shared_ddc = TRUE;
2637			    info->BiosConnector[j].shared_ddc = TRUE;
2638			}
2639			/* other possible combos?  */
2640		    }
2641		}
2642	    }
2643	}
2644    }
2645
2646    return TRUE;
2647}
2648
2649# ifdef ATOM_BIOS_PARSER
2650static AtomBiosResult
2651rhdAtomExec (atomBiosHandlePtr handle,
2652	     AtomBiosRequestID unused, AtomBiosArgPtr data)
2653{
2654    RADEONInfoPtr info = RADEONPTR (handle->pScrn);
2655    Bool ret = FALSE;
2656    char *msg;
2657    int idx = data->exec.index;
2658    void *pspace = data->exec.pspace;
2659    pointer *dataSpace = data->exec.dataSpace;
2660
2661    //RHDFUNCI(handle->scrnIndex);
2662
2663    if (dataSpace) {
2664	if (!handle->fbBase && !handle->scratchBase)
2665	    return ATOM_FAILED;
2666	if (handle->fbBase) {
2667	    if (!info->FB) {
2668		xf86DrvMsg(handle->pScrn->scrnIndex, X_ERROR, "%s: "
2669			   "Cannot exec AtomBIOS: framebuffer not mapped\n",
2670			   __func__);
2671		return ATOM_FAILED;
2672	    }
2673	    *dataSpace = (uint8_t*)info->FB + handle->fbBase;
2674	} else
2675	    *dataSpace = (uint8_t*)handle->scratchBase;
2676    }
2677    ret = ParseTableWrapper(pspace, idx, handle,
2678			    handle->BIOSBase,
2679			    &msg);
2680    if (!ret)
2681	xf86DrvMsg(handle->pScrn->scrnIndex, X_ERROR, "%s\n",msg);
2682    else
2683	xf86DrvMsgVerb(handle->pScrn->scrnIndex, X_INFO, 5, "%s\n",msg);
2684
2685    return (ret) ? ATOM_SUCCESS : ATOM_FAILED;
2686}
2687# endif
2688
2689AtomBiosResult
2690RHDAtomBiosFunc(ScrnInfoPtr pScrn, atomBiosHandlePtr handle,
2691		AtomBiosRequestID id, AtomBiosArgPtr data)
2692{
2693    AtomBiosResult ret = ATOM_FAILED;
2694    int i;
2695    char *msg = NULL;
2696    enum msgDataFormat msg_f = MSG_FORMAT_NONE;
2697    AtomBiosRequestFunc req_func = NULL;
2698
2699    //RHDFUNCI(scrnIndex);
2700
2701    for (i = 0; AtomBiosRequestList[i].id != FUNC_END; i++) {
2702	if (id ==  AtomBiosRequestList[i].id) {
2703	    req_func = AtomBiosRequestList[i].request;
2704	    msg = AtomBiosRequestList[i].message;
2705	    msg_f = AtomBiosRequestList[i].message_format;
2706	    break;
2707	}
2708    }
2709
2710    if (req_func == NULL) {
2711	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unknown AtomBIOS request: %i\n",id);
2712	return ATOM_NOT_IMPLEMENTED;
2713    }
2714    /* Hack for now */
2715    if (id == ATOMBIOS_INIT)
2716	data->pScrn = pScrn;
2717
2718    if (id == ATOMBIOS_INIT || handle)
2719	ret = req_func(handle, id, data);
2720
2721    if (ret == ATOM_SUCCESS) {
2722
2723	switch (msg_f) {
2724	    case MSG_FORMAT_DEC:
2725		xf86DrvMsg(pScrn->scrnIndex,X_INFO,"%s: %li\n", msg,
2726			   (unsigned long) data->val);
2727		break;
2728	    case MSG_FORMAT_HEX:
2729		xf86DrvMsg(pScrn->scrnIndex,X_INFO,"%s: 0x%lx\n",msg ,
2730			   (unsigned long) data->val);
2731		break;
2732	    case MSG_FORMAT_NONE:
2733		xf86DrvMsgVerb(pScrn->scrnIndex, 7, X_INFO,
2734			       "Call to %s succeeded\n", msg);
2735		break;
2736	}
2737
2738    } else {
2739
2740	char *result = (ret == ATOM_FAILED) ? "failed"
2741	    : "not implemented";
2742	switch (msg_f) {
2743	    case MSG_FORMAT_DEC:
2744	    case MSG_FORMAT_HEX:
2745		xf86DrvMsgVerb(pScrn->scrnIndex, 1, X_WARNING,
2746			       "Call to %s %s\n", msg, result);
2747		break;
2748	    case MSG_FORMAT_NONE:
2749		xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Query for %s: %s\n", msg, result);
2750		    break;
2751	}
2752    }
2753    return ret;
2754}
2755
2756# ifdef ATOM_BIOS_PARSER
2757VOID*
2758CailAllocateMemory(VOID *CAIL,UINT16 size)
2759{
2760    void *ret;
2761    CAILFUNC(CAIL);
2762
2763    ret = malloc(size);
2764    memset(ret, 0, size);
2765    return ret;
2766}
2767
2768VOID
2769CailReleaseMemory(VOID *CAIL, VOID *addr)
2770{
2771    CAILFUNC(CAIL);
2772
2773    free(addr);
2774}
2775
2776VOID
2777CailDelayMicroSeconds(VOID *CAIL, UINT32 delay)
2778{
2779    CAILFUNC(CAIL);
2780
2781    usleep(delay);
2782
2783    /*DEBUGP(xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_INFO,"Delay %i usec\n",delay));*/
2784}
2785
2786UINT32
2787CailReadATIRegister(VOID* CAIL, UINT32 idx)
2788{
2789    ScrnInfoPtr pScrn = ((atomBiosHandlePtr)CAIL)->pScrn;
2790    RADEONInfoPtr info = RADEONPTR(pScrn);
2791    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2792    unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
2793    UINT32 ret;
2794    UINT32 mm_reg = idx << 2;
2795    CAILFUNC(CAIL);
2796
2797    if (mm_reg < info->MMIOSize)
2798	ret = INREG(mm_reg);
2799    else {
2800	OUTREG(RADEON_MM_INDEX, mm_reg);
2801	ret = INREG(RADEON_MM_DATA);
2802    }
2803
2804    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx << 2,ret));*/
2805    return ret;
2806}
2807
2808VOID
2809CailWriteATIRegister(VOID *CAIL, UINT32 idx, UINT32 data)
2810{
2811    ScrnInfoPtr pScrn = ((atomBiosHandlePtr)CAIL)->pScrn;
2812    RADEONInfoPtr info = RADEONPTR(pScrn);
2813    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2814    unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
2815    UINT32 mm_reg = idx << 2;
2816    CAILFUNC(CAIL);
2817
2818    if (mm_reg < info->MMIOSize)
2819	OUTREG(mm_reg, data);
2820    else {
2821	OUTREG(RADEON_MM_INDEX, mm_reg);
2822	OUTREG(RADEON_MM_DATA, data);
2823    }
2824
2825    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx << 2,data));*/
2826}
2827
2828UINT32
2829CailReadFBData(VOID* CAIL, UINT32 idx)
2830{
2831    ScrnInfoPtr pScrn = ((atomBiosHandlePtr)CAIL)->pScrn;
2832    RADEONInfoPtr  info   = RADEONPTR(pScrn);
2833    UINT32 ret;
2834
2835    CAILFUNC(CAIL);
2836
2837    if (((atomBiosHandlePtr)CAIL)->fbBase) {
2838	uint8_t *FBBase = (uint8_t*)info->FB;
2839	ret =  *((uint32_t*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx));
2840	/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,ret));*/
2841    } else if (((atomBiosHandlePtr)CAIL)->scratchBase) {
2842	ret = *(uint32_t*)((uint8_t*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx);
2843	/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,ret));*/
2844    } else {
2845	xf86DrvMsg(pScrn->scrnIndex,X_ERROR,
2846		   "%s: no fbbase set\n",__func__);
2847	return 0;
2848    }
2849    return ret;
2850}
2851
2852VOID
2853CailWriteFBData(VOID *CAIL, UINT32 idx, UINT32 data)
2854{
2855    ScrnInfoPtr pScrn = ((atomBiosHandlePtr)CAIL)->pScrn;
2856    CAILFUNC(CAIL);
2857
2858    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx,data));*/
2859    if (((atomBiosHandlePtr)CAIL)->fbBase) {
2860	uint8_t *FBBase = (uint8_t*)
2861	    RADEONPTR(pScrn)->FB;
2862	*((uint32_t*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx)) = data;
2863    } else if (((atomBiosHandlePtr)CAIL)->scratchBase) {
2864	*(uint32_t*)((uint8_t*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx) = data;
2865    } else
2866	xf86DrvMsg(pScrn->scrnIndex,X_ERROR,
2867		   "%s: no fbbase set\n",__func__);
2868}
2869
2870ULONG
2871CailReadMC(VOID *CAIL, ULONG Address)
2872{
2873    ScrnInfoPtr pScrn = ((atomBiosHandlePtr)CAIL)->pScrn;
2874    ULONG ret;
2875
2876    CAILFUNC(CAIL);
2877
2878    ret = INMC(pScrn, Address);
2879    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,Address,ret));*/
2880    return ret;
2881}
2882
2883VOID
2884CailWriteMC(VOID *CAIL, ULONG Address, ULONG data)
2885{
2886    ScrnInfoPtr pScrn = ((atomBiosHandlePtr)CAIL)->pScrn;
2887
2888    CAILFUNC(CAIL);
2889    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,Address,data));*/
2890    OUTMC(pScrn, Address, data);
2891}
2892
2893#ifdef XSERVER_LIBPCIACCESS
2894
2895VOID
2896CailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size)
2897{
2898    ScrnInfoPtr pScrn = ((atomBiosHandlePtr)CAIL)->pScrn;
2899    pci_device_cfg_read(RADEONPTR(pScrn)->PciInfo,
2900				ret,idx << 2 , size >> 3, NULL);
2901}
2902
2903VOID
2904CailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size)
2905{
2906    ScrnInfoPtr pScrn = ((atomBiosHandlePtr)CAIL)->pScrn;
2907    pci_device_cfg_write(RADEONPTR(pScrn)->PciInfo,
2908			 src, idx << 2, size >> 3, NULL);
2909}
2910
2911#else
2912
2913VOID
2914CailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size)
2915{
2916    PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag;
2917
2918    CAILFUNC(CAIL);
2919
2920    switch (size) {
2921	case 8:
2922	    *(uint8_t*)ret = pciReadByte(tag,idx << 2);
2923	    break;
2924	case 16:
2925	    *(uint16_t*)ret = pciReadWord(tag,idx << 2);
2926	    break;
2927	case 32:
2928	    *(uint32_t*)ret = pciReadLong(tag,idx << 2);
2929	    break;
2930	default:
2931	xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,
2932		   X_ERROR,"%s: Unsupported size: %i\n",
2933		   __func__,(int)size);
2934	return;
2935	    break;
2936    }
2937    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,*(unsigned int*)ret));*/
2938
2939}
2940
2941VOID
2942CailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size)
2943{
2944    PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag;
2945
2946    CAILFUNC(CAIL);
2947    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx,(*(unsigned int*)src)));*/
2948    switch (size) {
2949	case 8:
2950	    pciWriteByte(tag,idx << 2,*(uint8_t*)src);
2951	    break;
2952	case 16:
2953	    pciWriteWord(tag,idx << 2,*(uint16_t*)src);
2954	    break;
2955	case 32:
2956	    pciWriteLong(tag,idx << 2,*(uint32_t*)src);
2957	    break;
2958	default:
2959	    xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
2960		       "%s: Unsupported size: %i\n",__func__,(int)size);
2961	    break;
2962    }
2963}
2964#endif
2965
2966ULONG
2967CailReadPLL(VOID *CAIL, ULONG Address)
2968{
2969    ScrnInfoPtr pScrn = ((atomBiosHandlePtr)CAIL)->pScrn;
2970    ULONG ret;
2971
2972    CAILFUNC(CAIL);
2973
2974    ret = RADEONINPLL(pScrn, Address);
2975    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,Address,ret));*/
2976    return ret;
2977}
2978
2979VOID
2980CailWritePLL(VOID *CAIL, ULONG Address,ULONG Data)
2981{
2982    ScrnInfoPtr pScrn = ((atomBiosHandlePtr)CAIL)->pScrn;
2983    CAILFUNC(CAIL);
2984
2985    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,Address,Data));*/
2986    RADEONOUTPLL(pScrn, Address, Data);
2987}
2988
2989void
2990atombios_get_command_table_version(atomBiosHandlePtr atomBIOS, int index, int *major, int *minor)
2991{
2992    ATOM_MASTER_COMMAND_TABLE *cmd_table = (void *)(atomBIOS->BIOSBase + atomBIOS->cmd_offset);
2993    ATOM_MASTER_LIST_OF_COMMAND_TABLES *table_start;
2994    ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *table_hdr;
2995
2996    //unsigned short *ptr;
2997    unsigned short offset;
2998
2999    table_start = &cmd_table->ListOfCommandTables;
3000
3001    offset  = *(((unsigned short *)table_start) + index);
3002
3003    offset = le16_to_cpu(offset);
3004    table_hdr = (ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *)(atomBIOS->BIOSBase + offset);
3005
3006    *major = table_hdr->CommonHeader.ucTableFormatRevision;
3007    *minor = table_hdr->CommonHeader.ucTableContentRevision;
3008}
3009
3010
3011UINT16 ATOM_BSWAP16(UINT16 x)
3012{
3013    return bswap_16(x);
3014}
3015
3016UINT32 ATOM_BSWAP32(UINT32 x)
3017{
3018    return bswap_32(x);
3019}
3020
3021
3022#endif /* ATOM_BIOS */
3023