radeon_atombios.c revision ad43ddac
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))->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->scrnIndex, handle, GET_FW_FB_SIZE, &data)
418	== ATOM_SUCCESS) {
419	if (data.val == 0) {
420	    xf86DrvMsg(handle->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->scrnIndex, 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->scrnIndex, X_INFO, "AtomBIOS requests %ikB"
454		   " of VRAM scratch space\n",fb_size);
455	fb_size *= 1024; /* convert to bytes */
456	xf86DrvMsg(handle->scrnIndex, X_INFO, "AtomBIOS VRAM scratch base: 0x%x\n",
457		   fb_base);
458    } else {
459	    fb_size = 20 * 1024;
460	    xf86DrvMsg(handle->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->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->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->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->scrnIndex, X_INFO,
491		   "Cannot get VRAM scratch space. "
492		   "Allocating in main memory instead\n");
493	handle->scratchBase = xcalloc(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->scrnIndex, handle,
507		    GET_DEFAULT_ENGINE_CLOCK,
508		    &data);
509    asicInit.sASICInitClocks.ulDefaultEngineClock = cpu_to_le32(data.val / 10);/*in 10 Khz*/
510    RHDAtomBiosFunc(handle->scrnIndex, 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->scrnIndex, X_INFO, "Calling ASIC Init\n");
518    if (RHDAtomBiosFunc(handle->scrnIndex, handle,
519			ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
520	xf86DrvMsg(handle->scrnIndex, X_INFO, "ASIC_INIT Successful\n");
521	return TRUE;
522    }
523    xf86DrvMsg(handle->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->scrnIndex, 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->scrnIndex, 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->scrnIndex, 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->scrnIndex, 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    int scrnIndex = data->val;
641    RADEONInfoPtr  info   = RADEONPTR(xf86Screens[scrnIndex]);
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 = xcalloc(1, sizeof(atomDataTables)))) {
655	xf86DrvMsg(scrnIndex,X_ERROR,"Cannot allocate memory for "
656		   "ATOM BIOS data tabes\n");
657	goto error;
658    }
659    if (!rhdAtomGetDataTable(scrnIndex, info->VBIOS, atomDataPtr, &cmd_offset, BIOSImageSize))
660	goto error1;
661    if (!(handle = xcalloc(1, sizeof(atomBiosHandleRec)))) {
662	xf86DrvMsg(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->scrnIndex = scrnIndex;
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    xfree(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    xfree(handle->BIOSBase);
692    xfree(handle->atomDataPtr);
693    if (handle->scratchBase) xfree(handle->scratchBase);
694    xfree(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)xcalloc(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 = 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 = 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 = dtd->usHActive + le16_to_cpu(dtd->usHSyncOffset);
792    mode->CrtcHSyncEnd = mode->HSyncEnd = mode->HSyncStart + le16_to_cpu(dtd->usHSyncWidth);
793    mode->CrtcVSyncStart = mode->VSyncStart = 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 *)xalloc(
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->scrnIndex,EDIDBlock);
873		    xf86PrintEDID(mon);
874		    xfree(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->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->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->scrnIndex, 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_COMMON_TABLE_HEADER)) /
1537	    sizeof(ATOM_GPIO_I2C_ASSIGMENT);
1538
1539    for (i = 0; i < num_indices; i++) {
1540	    gpio = &atomDataPtr->GPIO_I2C_Info->asGPIO_Info[i];
1541	    if (gpio->sucI2cId.ucAccess == id) {
1542		    i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
1543		    i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
1544		    i2c.put_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
1545		    i2c.put_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
1546		    i2c.get_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
1547		    i2c.get_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
1548		    i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
1549		    i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
1550		    i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
1551		    i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
1552		    i2c.put_clk_mask = (1 << gpio->ucClkEnShift);
1553		    i2c.put_data_mask = (1 << gpio->ucDataEnShift);
1554		    i2c.get_clk_mask = (1 << gpio->ucClkY_Shift);
1555		    i2c.get_data_mask = (1 <<  gpio->ucDataY_Shift);
1556		    i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
1557		    i2c.a_data_mask = (1 <<  gpio->ucDataA_Shift);
1558		    i2c.hw_line = gpio->sucI2cId.ucAccess;
1559		    i2c.hw_capable = gpio->sucI2cId.sbfAccess.bfHW_Capable;
1560		    i2c.valid = TRUE;
1561		    break;
1562	    }
1563    }
1564
1565#if 0
1566    ErrorF("id: %d\n", id);
1567    ErrorF("hw capable: %d\n", gpio->sucI2cId.sbfAccess.bfHW_Capable);
1568    ErrorF("hw engine id: %d\n", gpio->sucI2cId.sbfAccess.bfHW_EngineID);
1569    ErrorF("line mux %d\n", gpio->sucI2cId.sbfAccess.bfI2C_LineMux);
1570    ErrorF("mask_clk_reg: 0x%x\n", gpio->usClkMaskRegisterIndex * 4);
1571    ErrorF("mask_data_reg: 0x%x\n", gpio->usDataMaskRegisterIndex * 4);
1572    ErrorF("put_clk_reg: 0x%x\n", gpio->usClkEnRegisterIndex * 4);
1573    ErrorF("put_data_reg: 0x%x\n", gpio->usDataEnRegisterIndex * 4);
1574    ErrorF("get_clk_reg: 0x%x\n", gpio->usClkY_RegisterIndex * 4);
1575    ErrorF("get_data_reg: 0x%x\n", gpio->usDataY_RegisterIndex * 4);
1576    ErrorF("a_clk_reg: 0x%x\n", gpio->usClkA_RegisterIndex * 4);
1577    ErrorF("a_data_reg: 0x%x\n", gpio->usDataA_RegisterIndex * 4);
1578    ErrorF("mask_clk_mask: %d\n", gpio->ucClkMaskShift);
1579    ErrorF("mask_data_mask: %d\n", gpio->ucDataMaskShift);
1580    ErrorF("put_clk_mask: %d\n", gpio->ucClkEnShift);
1581    ErrorF("put_data_mask: %d\n", gpio->ucDataEnShift);
1582    ErrorF("get_clk_mask: %d\n", gpio->ucClkY_Shift);
1583    ErrorF("get_data_mask: %d\n", gpio->ucDataY_Shift);
1584    ErrorF("a_clk_mask: %d\n", gpio->ucClkA_Shift);
1585    ErrorF("a_data_mask: %d\n", gpio->ucDataA_Shift);
1586#endif
1587
1588    return i2c;
1589}
1590
1591static RADEONI2CBusRec
1592rhdAtomParseI2CRecord(ScrnInfoPtr pScrn, atomBiosHandlePtr handle,
1593		      ATOM_I2C_RECORD *Record, int i)
1594{
1595    RADEONInfoPtr info = RADEONPTR (pScrn);
1596    uint8_t *temp = &Record->sucI2cId;
1597
1598    info->BiosConnector[i].i2c_line_mux = *temp;
1599    info->BiosConnector[i].ucI2cId = *temp;
1600    return RADEONLookupGPIOLineForDDC(pScrn, *temp);
1601}
1602
1603static uint8_t
1604radeon_lookup_hpd_id(ScrnInfoPtr pScrn, ATOM_HPD_INT_RECORD *record)
1605{
1606    RADEONInfoPtr info = RADEONPTR (pScrn);
1607    unsigned short size;
1608    uint8_t hpd = 0;
1609    int i, num_indices;
1610    struct _ATOM_GPIO_PIN_LUT *gpio_info;
1611    ATOM_GPIO_PIN_ASSIGNMENT *pin;
1612    atomDataTablesPtr atomDataPtr;
1613    uint8_t crev, frev;
1614    uint32_t reg;
1615
1616    atomDataPtr = info->atomBIOS->atomDataPtr;
1617
1618    if (!rhdAtomGetTableRevisionAndSize(
1619	    &(atomDataPtr->GPIO_Pin_LUT->sHeader),
1620	    &crev,&frev,&size)) {
1621	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No GPIO Pin Table found!\n");
1622	return hpd;
1623    }
1624
1625    num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
1626
1627    if (IS_DCE4_VARIANT)
1628	reg = EVERGREEN_DC_GPIO_HPD_A;
1629    else
1630	reg = AVIVO_DC_GPIO_HPD_A;
1631
1632    gpio_info = atomDataPtr->GPIO_Pin_LUT;
1633    for (i = 0; i < num_indices; i++) {
1634	pin = &gpio_info->asGPIO_Pin[i];
1635	if (record->ucHPDIntGPIOID == pin->ucGPIO_ID) {
1636	    if ((pin->usGpioPin_AIndex * 4) == reg) {
1637		switch (pin->ucGpioPinBitShift) {
1638		case 0:
1639		default:
1640		    hpd = 0;
1641		    break;
1642		case 8:
1643		    hpd = 1;
1644		    break;
1645		case 16:
1646		    hpd = 2;
1647		    break;
1648		case 24:
1649		    hpd = 3;
1650		    break;
1651		case 26:
1652		    hpd = 4;
1653		    break;
1654		case 28:
1655		    hpd = 5;
1656		    break;
1657		}
1658		break;
1659	    }
1660	}
1661    }
1662
1663    return hpd;
1664}
1665
1666static void RADEONApplyATOMQuirks(ScrnInfoPtr pScrn, int index)
1667{
1668    RADEONInfoPtr info = RADEONPTR (pScrn);
1669
1670    /* Asus M2A-VM HDMI board lists the DVI port as HDMI */
1671    if ((info->Chipset == PCI_CHIP_RS690_791E) &&
1672	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1673	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x826d)) {
1674	if ((info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) &&
1675	    (info->BiosConnector[index].devices & ATOM_DEVICE_DFP3_SUPPORT)) {
1676	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D;
1677	}
1678    }
1679
1680    /* RS600 board lists the DVI port as HDMI */
1681    if ((info->Chipset == PCI_CHIP_RS600_7941) &&
1682	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1849) &&
1683	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x7941)) {
1684	if ((info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) &&
1685	    (info->BiosConnector[index].devices & ATOM_DEVICE_DFP3_SUPPORT)) {
1686	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D;
1687	}
1688    }
1689
1690    /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
1691    if ((info->Chipset == PCI_CHIP_RS600_7941) &&
1692	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x147b) &&
1693	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x2412)) {
1694	if (info->BiosConnector[index].ConnectorType == CONNECTOR_DVI_I)
1695	    info->BiosConnector[index].valid = FALSE;
1696    }
1697
1698    /* Falcon NW laptop lists vga ddc line for LVDS */
1699    if ((info->Chipset == PCI_CHIP_RV410_5653) &&
1700	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1462) &&
1701	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0291)) {
1702	if (info->BiosConnector[index].ConnectorType == CONNECTOR_LVDS) {
1703	    info->BiosConnector[index].ddc_i2c.valid = FALSE;
1704	}
1705    }
1706
1707    /* Funky macbooks */
1708    if ((info->Chipset == PCI_CHIP_RV530_71C5) &&
1709	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) &&
1710	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) {
1711	if ((index == ATOM_DEVICE_CRT1_INDEX) ||
1712	    (index == ATOM_DEVICE_CRT2_INDEX) ||
1713	    (index == ATOM_DEVICE_DFP2_INDEX))
1714	    info->BiosConnector[index].valid = FALSE;
1715
1716	if (index == ATOM_DEVICE_DFP1_INDEX) {
1717	    info->BiosConnector[index].devices |= ATOM_DEVICE_CRT2_SUPPORT;
1718	}
1719    }
1720
1721    /* ASUS HD 3600 XT board lists the DVI port as HDMI */
1722    if ((info->Chipset == PCI_CHIP_RV635_9598) &&
1723	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1724	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01da)) {
1725	if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A)
1726	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_I;
1727    }
1728
1729    /* ASUS HD 3450 board lists the DVI port as HDMI */
1730    if ((info->Chipset == PCI_CHIP_RV620_95C5) &&
1731	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1732	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01e2)) {
1733	if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A)
1734	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_I;
1735    }
1736
1737    /* some BIOSes seem to report DAC on HDMI - usually this is a board with
1738     * HDMI + VGA reporting as HDMI
1739     */
1740    if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) {
1741	if (info->BiosConnector[index].devices & (ATOM_DEVICE_CRT_SUPPORT)) {
1742	    info->BiosConnector[index].devices &= ~(ATOM_DEVICE_DFP_SUPPORT);
1743	    info->BiosConnector[index].ConnectorType = CONNECTOR_VGA;
1744	    info->BiosConnector[index].connector_object = 0;
1745	}
1746    }
1747
1748}
1749
1750uint32_t
1751radeon_get_device_index(uint32_t device_support)
1752{
1753    uint32_t device_index = 0;
1754
1755    if (device_support == 0)
1756	return 0;
1757
1758    while ((device_support & 1) == 0) {
1759	device_support >>= 1;
1760	device_index++;
1761    }
1762    return device_index;
1763}
1764
1765radeon_encoder_ptr
1766radeon_get_encoder(xf86OutputPtr output)
1767{
1768    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1769    RADEONInfoPtr info = RADEONPTR(output->scrn);
1770
1771    if (radeon_output->active_device)
1772	return info->encoders[radeon_get_device_index(radeon_output->active_device)];
1773    else
1774	return NULL;
1775}
1776
1777Bool
1778radeon_add_encoder(ScrnInfoPtr pScrn, uint32_t encoder_id, uint32_t device_support)
1779{
1780    RADEONInfoPtr info = RADEONPTR (pScrn);
1781    uint32_t device_index = radeon_get_device_index(device_support);
1782    int i;
1783
1784    if (device_support == 0) {
1785	ErrorF("device support == 0\n");
1786	return FALSE;
1787    }
1788
1789    if (info->encoders[device_index] != NULL)
1790	return TRUE;
1791    else {
1792	/* look for the encoder */
1793	for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
1794	    if ((info->encoders[i] != NULL) && (info->encoders[i]->encoder_id == encoder_id)) {
1795		info->encoders[device_index] = info->encoders[i];
1796		switch (encoder_id) {
1797		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1798		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1799		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1800		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1801		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1802		    if (device_support & ATOM_DEVICE_LCD1_SUPPORT) {
1803			if (info->encoders[device_index]->dev_priv == NULL) {
1804			    info->encoders[device_index]->dev_priv =
1805				(radeon_lvds_ptr)xcalloc(1,sizeof(radeon_lvds_rec));
1806			    if (info->encoders[device_index]->dev_priv == NULL) {
1807				ErrorF("xalloc failed\n");
1808				return FALSE;
1809			    } else
1810				RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1811			}
1812		    }
1813		    break;
1814		}
1815		return TRUE;
1816	    }
1817	}
1818
1819	info->encoders[device_index] = (radeon_encoder_ptr)xcalloc(1,sizeof(radeon_encoder_rec));
1820	if (info->encoders[device_index] != NULL) {
1821	    info->encoders[device_index]->encoder_id = encoder_id;
1822	    info->encoders[device_index]->devices = 0;
1823	    info->encoders[device_index]->dev_priv = NULL;
1824	    // add dev_priv stuff
1825	    switch (encoder_id) {
1826	    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1827		    info->encoders[device_index]->dev_priv = (radeon_lvds_ptr)xcalloc(1,sizeof(radeon_lvds_rec));
1828		    if (info->encoders[device_index]->dev_priv == NULL) {
1829			ErrorF("xalloc failed\n");
1830			return FALSE;
1831		    } else {
1832			if (info->IsAtomBios)
1833			    RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1834			else
1835			    RADEONGetLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1836		    }
1837		break;
1838	    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1839		if (!IS_AVIVO_VARIANT) {
1840		    info->encoders[device_index]->dev_priv = (radeon_tvdac_ptr)xcalloc(1,sizeof(radeon_tvdac_rec));
1841		    if (info->encoders[device_index]->dev_priv == NULL) {
1842			ErrorF("xalloc failed\n");
1843			return FALSE;
1844		    } else
1845			RADEONGetTVDacAdjInfo(pScrn, (radeon_tvdac_ptr)info->encoders[device_index]->dev_priv);
1846		}
1847		break;
1848	    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1849		if (!IS_AVIVO_VARIANT) {
1850		    info->encoders[device_index]->dev_priv = (radeon_tmds_ptr)xcalloc(1,sizeof(radeon_tmds_rec));
1851		    if (info->encoders[device_index]->dev_priv == NULL) {
1852			ErrorF("xalloc failed\n");
1853			return FALSE;
1854		    } else
1855			RADEONGetTMDSInfo(pScrn, (radeon_tmds_ptr)info->encoders[device_index]->dev_priv);
1856		}
1857		break;
1858	    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1859		if (!IS_AVIVO_VARIANT) {
1860		    info->encoders[device_index]->dev_priv = (radeon_dvo_ptr)xcalloc(1,sizeof(radeon_dvo_rec));
1861		    if (info->encoders[device_index]->dev_priv == NULL) {
1862			ErrorF("xalloc failed\n");
1863			return FALSE;
1864		    } else
1865			RADEONGetExtTMDSInfo(pScrn, (radeon_dvo_ptr)info->encoders[device_index]->dev_priv);
1866		}
1867		break;
1868	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1869	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1870	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1871	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1872	    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1873		if (device_support & ATOM_DEVICE_LCD1_SUPPORT) {
1874		    info->encoders[device_index]->dev_priv = (radeon_lvds_ptr)xcalloc(1,sizeof(radeon_lvds_rec));
1875		    if (info->encoders[device_index]->dev_priv == NULL) {
1876			ErrorF("xalloc failed\n");
1877			return FALSE;
1878		    } else
1879			RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1880		}
1881		break;
1882	    }
1883	    return TRUE;
1884	} else {
1885	    ErrorF("xalloc failed\n");
1886	    return FALSE;
1887	}
1888    }
1889
1890}
1891
1892Bool
1893RADEONGetATOMConnectorInfoFromBIOSObject (ScrnInfoPtr pScrn)
1894{
1895    RADEONInfoPtr info = RADEONPTR (pScrn);
1896    uint8_t crev, frev;
1897    unsigned short size;
1898    atomDataTablesPtr atomDataPtr;
1899    ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
1900    ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
1901    ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj = NULL;
1902    int i, j, path_size, device_support;
1903    Bool enable_tv = FALSE;
1904
1905    if (xf86ReturnOptValBool(info->Options, OPTION_ATOM_TVOUT, FALSE))
1906	enable_tv = TRUE;
1907
1908    atomDataPtr = info->atomBIOS->atomDataPtr;
1909    if (!rhdAtomGetTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->Object_Header), &crev, &frev, &size))
1910	return FALSE;
1911
1912    if (crev < 2)
1913	return FALSE;
1914
1915    path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
1916	((char *)&atomDataPtr->Object_Header->sHeader +
1917	 le16_to_cpu(atomDataPtr->Object_Header->usDisplayPathTableOffset));
1918    con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
1919	((char *)&atomDataPtr->Object_Header->sHeader +
1920	 le16_to_cpu(atomDataPtr->Object_Header->usConnectorObjectTableOffset));
1921    device_support = le16_to_cpu(atomDataPtr->Object_Header->usDeviceSupport);
1922
1923    path_size = 0;
1924    for (i = 0; i < path_obj->ucNumOfDispPath; i++) {
1925	uint8_t *addr = (uint8_t *)path_obj->asDispPath;
1926	ATOM_DISPLAY_OBJECT_PATH *path;
1927	addr += path_size;
1928	path = (ATOM_DISPLAY_OBJECT_PATH *)addr;
1929	path_size += le16_to_cpu(path->usSize);
1930
1931	if (device_support & le16_to_cpu(path->usDeviceTag)) {
1932	    uint8_t con_obj_id, con_obj_num, con_obj_type;
1933
1934	    con_obj_id = (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
1935	    con_obj_num = (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
1936	    con_obj_type = (le16_to_cpu(path->usConnObjectId) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
1937
1938	    if ((le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_TV1_SUPPORT) ||
1939		(le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_TV2_SUPPORT)) {
1940		if (!enable_tv) {
1941		    info->BiosConnector[i].valid = FALSE;
1942		    continue;
1943		}
1944	    }
1945
1946	    /* don't support CV yet */
1947	    if (le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_CV_SUPPORT) {
1948		info->BiosConnector[i].valid = FALSE;
1949		continue;
1950	    }
1951
1952	    if (info->IsIGP &&
1953		(con_obj_id == CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) {
1954		uint32_t slot_config, ct;
1955
1956		igp_obj = info->atomBIOS->atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2;
1957
1958		if (!igp_obj)
1959		    info->BiosConnector[i].ConnectorType = object_connector_convert[con_obj_id];
1960		else {
1961		    if (con_obj_num == 1)
1962			slot_config = igp_obj->ulDDISlot1Config;
1963		    else
1964			slot_config = igp_obj->ulDDISlot2Config;
1965
1966		    ct = (slot_config  >> 16) & 0xff;
1967		    info->BiosConnector[i].ConnectorType = object_connector_convert[ct];
1968		    info->BiosConnector[i].connector_object_id = ct;
1969		    info->BiosConnector[i].igp_lane_info = slot_config & 0xffff;
1970		}
1971	    } else {
1972		info->BiosConnector[i].ConnectorType = object_connector_convert[con_obj_id];
1973		info->BiosConnector[i].connector_object_id = con_obj_id;
1974	    }
1975
1976	    if (info->BiosConnector[i].ConnectorType == CONNECTOR_NONE) {
1977		info->BiosConnector[i].valid = FALSE;
1978		continue;
1979	    } else
1980		info->BiosConnector[i].valid = TRUE;
1981	    info->BiosConnector[i].devices = le16_to_cpu(path->usDeviceTag);
1982	    info->BiosConnector[i].connector_object = le16_to_cpu(path->usConnObjectId);
1983
1984	    for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
1985		uint8_t enc_obj_id, enc_obj_num, enc_obj_type;
1986
1987		enc_obj_id = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
1988		enc_obj_num = (le16_to_cpu(path->usGraphicObjIds[j]) & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
1989		enc_obj_type = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
1990
1991		if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
1992		    if (enc_obj_num == 2)
1993			info->BiosConnector[i].linkb = TRUE;
1994		    else
1995			info->BiosConnector[i].linkb = FALSE;
1996
1997		    if (!radeon_add_encoder(pScrn, enc_obj_id, le16_to_cpu(path->usDeviceTag)))
1998			return FALSE;
1999		}
2000	    }
2001
2002	    /* look up gpio for ddc */
2003	    if ((le16_to_cpu(path->usDeviceTag) & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
2004		for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
2005		    if (le16_to_cpu(path->usConnObjectId) == le16_to_cpu(con_obj->asObjects[j].usObjectID)) {
2006			ATOM_COMMON_RECORD_HEADER *Record = (ATOM_COMMON_RECORD_HEADER *)
2007			    ((char *)&atomDataPtr->Object_Header->sHeader
2008			     + le16_to_cpu(con_obj->asObjects[j].usRecordOffset));
2009
2010			while (Record->ucRecordType > 0
2011			       && Record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER ) {
2012
2013			    /*ErrorF("record type %d\n", Record->ucRecordType);*/
2014			    switch (Record->ucRecordType) {
2015			    case ATOM_I2C_RECORD_TYPE:
2016				info->BiosConnector[i].ddc_i2c =
2017				    rhdAtomParseI2CRecord(pScrn, info->atomBIOS,
2018							  (ATOM_I2C_RECORD *)Record, j);
2019				break;
2020			    case ATOM_HPD_INT_RECORD_TYPE:
2021				info->BiosConnector[i].hpd_id =
2022				    radeon_lookup_hpd_id(pScrn,
2023							 (ATOM_HPD_INT_RECORD *)Record);
2024				break;
2025			    case ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE:
2026				break;
2027			    }
2028
2029			    Record = (ATOM_COMMON_RECORD_HEADER*)
2030				((char *)Record + Record->ucRecordSize);
2031			}
2032			break;
2033		    }
2034		}
2035	    }
2036	}
2037	RADEONApplyATOMQuirks(pScrn, i);
2038    }
2039
2040    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2041	if (info->BiosConnector[i].valid) {
2042	    /* shared connectors */
2043	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2044		if (info->BiosConnector[j].valid && (i != j) ) {
2045		    if (info->BiosConnector[i].connector_object == info->BiosConnector[j].connector_object) {
2046			info->BiosConnector[i].devices |= info->BiosConnector[j].devices;
2047			info->BiosConnector[j].valid = FALSE;
2048		    }
2049		}
2050	    }
2051	    /* shared ddc */
2052	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2053		if (info->BiosConnector[j].valid && (i != j) ) {
2054		    if (info->BiosConnector[i].i2c_line_mux == info->BiosConnector[j].i2c_line_mux) {
2055			info->BiosConnector[i].shared_ddc = TRUE;
2056			info->BiosConnector[j].shared_ddc = TRUE;
2057		    }
2058		}
2059	    }
2060	}
2061    }
2062
2063    return TRUE;
2064}
2065
2066static void
2067RADEONGetATOMLVDSInfo(ScrnInfoPtr pScrn, radeon_lvds_ptr lvds)
2068{
2069    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2070    radeon_native_mode_ptr native_mode = &lvds->native_mode;
2071    atomDataTablesPtr atomDataPtr;
2072    uint8_t crev, frev;
2073    uint16_t misc;
2074
2075    atomDataPtr = info->atomBIOS->atomDataPtr;
2076
2077    if (!rhdAtomGetTableRevisionAndSize(
2078	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
2079	    &frev,&crev,NULL)) {
2080	return;
2081    }
2082
2083    switch (crev) {
2084    case 1:
2085	native_mode->PanelXRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHActive);
2086	native_mode->PanelYRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVActive);
2087	native_mode->DotClock   = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usPixClk) * 10;
2088	native_mode->HBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHBlanking_Time);
2089	native_mode->HOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHSyncOffset);
2090	native_mode->HSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHSyncWidth);
2091	native_mode->VBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVBlanking_Time);
2092	native_mode->VOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVSyncOffset);
2093	native_mode->VSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVSyncWidth);
2094	misc = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.susModeMiscInfo.usAccess);
2095	if (misc & ATOM_VSYNC_POLARITY)
2096	    native_mode->Flags |= V_NVSYNC;
2097	if (misc & ATOM_HSYNC_POLARITY)
2098	    native_mode->Flags |= V_NHSYNC;
2099	if (misc & ATOM_COMPOSITESYNC)
2100	    native_mode->Flags |= V_CSYNC;
2101	if (misc & ATOM_INTERLACE)
2102	    native_mode->Flags |= V_INTERLACE;
2103	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2104	    native_mode->Flags |= V_DBLSCAN;
2105	lvds->PanelPwrDly = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->usOffDelayInMs);
2106	lvds->lvds_misc   =  atomDataPtr->LVDS_Info.LVDS_Info->ucLVDS_Misc;
2107	lvds->lvds_ss_id  =  atomDataPtr->LVDS_Info.LVDS_Info->ucSS_Id;
2108	break;
2109    case 2:
2110	native_mode->PanelXRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHActive);
2111	native_mode->PanelYRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVActive);
2112	native_mode->DotClock   = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usPixClk) * 10;
2113	native_mode->HBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHBlanking_Time);
2114	native_mode->HOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHSyncOffset);
2115	native_mode->HSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHSyncWidth);
2116	native_mode->VBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVBlanking_Time);
2117	native_mode->VOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVSyncOffset);
2118	native_mode->VSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVSyncWidth);
2119	misc = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.susModeMiscInfo.usAccess);
2120	if (misc & ATOM_VSYNC_POLARITY)
2121	    native_mode->Flags |= V_NVSYNC;
2122	if (misc & ATOM_HSYNC_POLARITY)
2123	    native_mode->Flags |= V_NHSYNC;
2124	if (misc & ATOM_COMPOSITESYNC)
2125	    native_mode->Flags |= V_CSYNC;
2126	if (misc & ATOM_INTERLACE)
2127	    native_mode->Flags |= V_INTERLACE;
2128	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2129	    native_mode->Flags |= V_DBLSCAN;
2130	lvds->PanelPwrDly = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->usOffDelayInMs);
2131	lvds->lvds_misc   =  atomDataPtr->LVDS_Info.LVDS_Info_v12->ucLVDS_Misc;
2132	lvds->lvds_ss_id  =  atomDataPtr->LVDS_Info.LVDS_Info_v12->ucSS_Id;
2133	break;
2134    }
2135    native_mode->Flags = 0;
2136
2137    if (lvds->PanelPwrDly > 2000 || lvds->PanelPwrDly < 0)
2138	lvds->PanelPwrDly = 2000;
2139
2140    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2141	       "LVDS Info:\n"
2142	       "XRes: %d, YRes: %d, DotClock: %d\n"
2143	       "HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n"
2144	       "VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n",
2145	       native_mode->PanelXRes, native_mode->PanelYRes, native_mode->DotClock,
2146	       native_mode->HBlank, native_mode->HOverPlus, native_mode->HSyncWidth,
2147	       native_mode->VBlank, native_mode->VOverPlus, native_mode->VSyncWidth);
2148}
2149
2150void
2151RADEONATOMGetIGPInfo(ScrnInfoPtr pScrn)
2152{
2153    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2154    atomDataTablesPtr atomDataPtr;
2155    unsigned short size;
2156    uint8_t crev, frev;
2157
2158    atomDataPtr = info->atomBIOS->atomDataPtr;
2159
2160    if (!rhdAtomGetTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->IntegratedSystemInfo.base), &frev, &crev, &size))
2161	return;
2162
2163    switch (crev) {
2164    case 1:
2165	info->igp_sideport_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->ulBootUpMemoryClock / 100.0;
2166	info->igp_system_mclk = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usK8MemoryClock);
2167	info->igp_ht_link_clk = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usFSBClock);
2168	info->igp_ht_link_width = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->ucHTLinkWidth;
2169	break;
2170    case 2:
2171	info->igp_sideport_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulBootUpSidePortClock / 100.0;
2172	info->igp_system_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulBootUpUMAClock / 100.0;
2173	info->igp_ht_link_clk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulHTLinkFreq / 100.0;
2174	info->igp_ht_link_width = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->usMinHTLinkWidth);
2175	break;
2176    }
2177}
2178
2179Bool
2180RADEONGetATOMTVInfo(xf86OutputPtr output)
2181{
2182    ScrnInfoPtr pScrn = output->scrn;
2183    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2184    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2185    radeon_tvout_ptr tvout = &radeon_output->tvout;
2186    ATOM_ANALOG_TV_INFO *tv_info;
2187
2188    tv_info = info->atomBIOS->atomDataPtr->AnalogTV_Info.AnalogTV_Info;
2189
2190    if (!tv_info)
2191	return FALSE;
2192
2193    switch(tv_info->ucTV_BootUpDefaultStandard) {
2194    case NTSCJ_SUPPORT:
2195	tvout->default_tvStd = TV_STD_NTSC_J;
2196	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC-J\n");
2197	break;
2198    case PAL_SUPPORT:
2199	tvout->default_tvStd = TV_STD_PAL;
2200	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL\n");
2201	break;
2202    case PALM_SUPPORT:
2203	tvout->default_tvStd = TV_STD_PAL_M;
2204	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-M\n");
2205	break;
2206    case PAL60_SUPPORT:
2207	tvout->default_tvStd = TV_STD_PAL_60;
2208	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-60\n");
2209	break;
2210    default:
2211    case NTSC_SUPPORT:
2212	tvout->default_tvStd = TV_STD_NTSC;
2213	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC\n");
2214	break;
2215    }
2216
2217    tvout->tvStd = tvout->default_tvStd;
2218
2219    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standards supported by chip: ");
2220    tvout->SupportedTVStds = tvout->default_tvStd;
2221    if (tv_info->ucTV_SupportedStandard & NTSC_SUPPORT) {
2222	ErrorF("NTSC ");
2223	tvout->SupportedTVStds |= TV_STD_NTSC;
2224    }
2225    if (tv_info->ucTV_SupportedStandard & NTSCJ_SUPPORT) {
2226	ErrorF("NTSC-J ");
2227	tvout->SupportedTVStds |= TV_STD_NTSC_J;
2228    }
2229    if (tv_info->ucTV_SupportedStandard & PAL_SUPPORT) {
2230	ErrorF("PAL ");
2231	tvout->SupportedTVStds |= TV_STD_PAL;
2232    }
2233    if (tv_info->ucTV_SupportedStandard & PALM_SUPPORT) {
2234	ErrorF("PAL-M ");
2235	tvout->SupportedTVStds |= TV_STD_PAL_M;
2236    }
2237    if (tv_info->ucTV_SupportedStandard & PAL60_SUPPORT) {
2238	ErrorF("PAL-60 ");
2239	tvout->SupportedTVStds |= TV_STD_PAL_60;
2240    }
2241    ErrorF("\n");
2242
2243    if (tv_info->ucExt_TV_ASIC_ID) {
2244	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unknown external TV ASIC\n");
2245	return FALSE;
2246    }
2247
2248    return TRUE;
2249}
2250
2251Bool
2252RADEONGetATOMClockInfo(ScrnInfoPtr pScrn)
2253{
2254    RADEONInfoPtr info = RADEONPTR (pScrn);
2255    RADEONPLLPtr pll = &info->pll;
2256    atomDataTablesPtr atomDataPtr;
2257    uint8_t crev, frev;
2258
2259    atomDataPtr = info->atomBIOS->atomDataPtr;
2260    if (!rhdAtomGetTableRevisionAndSize(
2261	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->FirmwareInfo.base),
2262	    &crev,&frev,NULL)) {
2263	return FALSE;
2264    }
2265
2266    switch(crev) {
2267    case 1:
2268	info->sclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulDefaultEngineClock) / 100.0;
2269	info->mclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulDefaultMemoryClock) / 100.0;
2270	pll->xclk = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMaxPixelClock);
2271	pll->pll_in_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMinPixelClockPLL_Input);
2272	pll->pll_in_max = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMaxPixelClockPLL_Input);
2273	pll->pll_out_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMinPixelClockPLL_Output);
2274	pll->pll_out_max = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulMaxPixelClockPLL_Output);
2275	pll->reference_freq = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usReferenceClock);
2276	break;
2277    case 2:
2278    case 3:
2279    case 4:
2280    default:
2281	info->sclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulDefaultEngineClock) / 100.0;
2282	info->mclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulDefaultMemoryClock) / 100.0;
2283	pll->xclk = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMaxPixelClock);
2284	pll->pll_in_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMinPixelClockPLL_Input);
2285	pll->pll_in_max = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMaxPixelClockPLL_Input);
2286	pll->pll_out_min = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulMinPixelClockPLL_Output);
2287	pll->pll_out_max = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulMaxPixelClockPLL_Output);
2288	pll->reference_freq = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usReferenceClock);
2289	break;
2290    }
2291    pll->reference_div = 0;
2292    if (pll->pll_out_min == 0)
2293	pll->pll_out_min = 64800;
2294
2295
2296    /* limiting the range is a good thing in most cases
2297     * as it limits the number of matching pll combinations,
2298     * however, some duallink DVI monitors seem to prefer combinations that
2299     * would be limited by this.  This may need to be revisited
2300     * per chip family.
2301     */
2302    if (!xf86ReturnOptValBool(info->Options, OPTION_NEW_PLL, TRUE)) {
2303	if (pll->pll_out_min > 64800)
2304	    pll->pll_out_min = 64800;
2305    }
2306
2307    return TRUE;
2308}
2309
2310Bool
2311RADEONATOMGetTVTimings(ScrnInfoPtr pScrn, int index, DisplayModePtr mode)
2312{
2313    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2314    ATOM_ANALOG_TV_INFO *tv_info;
2315    ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2;
2316    ATOM_DTD_FORMAT *dtd_timings;
2317    atomDataTablesPtr atomDataPtr;
2318    uint8_t crev, frev;
2319    uint16_t misc;
2320
2321    atomDataPtr = info->atomBIOS->atomDataPtr;
2322    if (!rhdAtomGetTableRevisionAndSize(
2323	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->AnalogTV_Info.base),
2324	    &crev,&frev,NULL)) {
2325	return FALSE;
2326    }
2327
2328    switch(crev) {
2329    case 1:
2330	tv_info = atomDataPtr->AnalogTV_Info.AnalogTV_Info;
2331
2332	if (index > MAX_SUPPORTED_TV_TIMING)
2333	    return FALSE;
2334
2335	mode->CrtcHTotal     = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
2336	mode->CrtcHDisplay   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
2337	mode->CrtcHSyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
2338	mode->CrtcHSyncEnd   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) +
2339	                       le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
2340
2341	mode->CrtcVTotal     = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
2342	mode->CrtcVDisplay   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
2343	mode->CrtcVSyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
2344	mode->CrtcVSyncEnd   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) +
2345	                       le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
2346
2347	mode->Flags = 0;
2348	misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess);
2349	if (misc & ATOM_VSYNC_POLARITY)
2350	    mode->Flags |= V_NVSYNC;
2351	if (misc & ATOM_HSYNC_POLARITY)
2352	    mode->Flags |= V_NHSYNC;
2353	if (misc & ATOM_COMPOSITESYNC)
2354	    mode->Flags |= V_CSYNC;
2355	if (misc & ATOM_INTERLACE)
2356	    mode->Flags |= V_INTERLACE;
2357	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2358	    mode->Flags |= V_DBLSCAN;
2359
2360	mode->Clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
2361
2362	if (index == 1) {
2363		/* PAL timings appear to have wrong values for totals */
2364		mode->CrtcHTotal -= 1;
2365		mode->CrtcVTotal -= 1;
2366	}
2367	break;
2368    case 2:
2369	tv_info_v1_2 = atomDataPtr->AnalogTV_Info.AnalogTV_Info_v1_2;
2370	if (index > MAX_SUPPORTED_TV_TIMING_V1_2)
2371	    return FALSE;
2372
2373	dtd_timings = &tv_info_v1_2->aModeTimings[index];
2374	mode->CrtcHTotal     = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHBlanking_Time);
2375	mode->CrtcHDisplay   = le16_to_cpu(dtd_timings->usHActive);
2376	mode->CrtcHSyncStart = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHSyncOffset);
2377	mode->CrtcHSyncEnd   = mode->CrtcHSyncStart + le16_to_cpu(dtd_timings->usHSyncWidth);
2378
2379	mode->CrtcVTotal     = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVBlanking_Time);
2380	mode->CrtcVDisplay   = le16_to_cpu(dtd_timings->usVActive);
2381	mode->CrtcVSyncStart = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVSyncOffset);
2382	mode->CrtcVSyncEnd   = mode->CrtcVSyncStart + le16_to_cpu(dtd_timings->usVSyncWidth);
2383
2384	mode->Flags = 0;
2385	misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
2386	if (misc & ATOM_VSYNC_POLARITY)
2387	    mode->Flags |= V_NVSYNC;
2388	if (misc & ATOM_HSYNC_POLARITY)
2389	    mode->Flags |= V_NHSYNC;
2390	if (misc & ATOM_COMPOSITESYNC)
2391	    mode->Flags |= V_CSYNC;
2392	if (misc & ATOM_INTERLACE)
2393	    mode->Flags |= V_INTERLACE;
2394	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2395	    mode->Flags |= V_DBLSCAN;
2396
2397	mode->Clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
2398
2399	break;
2400    }
2401
2402    return TRUE;
2403}
2404
2405uint32_t
2406radeon_get_encoder_id_from_supported_device(ScrnInfoPtr pScrn, uint32_t supported_device, int dac)
2407{
2408    RADEONInfoPtr info = RADEONPTR (pScrn);
2409    uint32_t ret = 0;
2410
2411    switch (supported_device) {
2412    case ATOM_DEVICE_CRT1_SUPPORT:
2413    case ATOM_DEVICE_TV1_SUPPORT:
2414    case ATOM_DEVICE_TV2_SUPPORT:
2415    case ATOM_DEVICE_CRT2_SUPPORT:
2416    case ATOM_DEVICE_CV_SUPPORT:
2417	switch (dac) {
2418	    // primary dac
2419	case 1:
2420	    if ((info->ChipFamily == CHIP_FAMILY_RS300) ||
2421		(info->ChipFamily == CHIP_FAMILY_RS400) ||
2422		(info->ChipFamily == CHIP_FAMILY_RS480))
2423		ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
2424	    else if (IS_AVIVO_VARIANT)
2425		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1;
2426	    else
2427		ret = ENCODER_OBJECT_ID_INTERNAL_DAC1;
2428	    break;
2429	    // secondary dac
2430	case 2:
2431	    if (IS_AVIVO_VARIANT)
2432		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2;
2433	    else {
2434		/*if (info->ChipFamily == CHIP_FAMILY_R200)
2435		    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2436		    else*/
2437		    ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
2438	    }
2439	    break;
2440	    // external dac
2441	case 3:
2442	    if (IS_AVIVO_VARIANT)
2443		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
2444	    else
2445		ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2446	    break;
2447	}
2448	break;
2449    case ATOM_DEVICE_LCD1_SUPPORT:
2450	if (IS_AVIVO_VARIANT)
2451	    ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
2452	else
2453	    ret = ENCODER_OBJECT_ID_INTERNAL_LVDS;
2454	break;
2455    case ATOM_DEVICE_DFP1_SUPPORT:
2456	if ((info->ChipFamily == CHIP_FAMILY_RS300) ||
2457	    (info->ChipFamily == CHIP_FAMILY_RS400) ||
2458	    (info->ChipFamily == CHIP_FAMILY_RS480))
2459	    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2460	else if (IS_AVIVO_VARIANT)
2461	    ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1;
2462	else
2463	    ret = ENCODER_OBJECT_ID_INTERNAL_TMDS1;
2464	break;
2465    case ATOM_DEVICE_LCD2_SUPPORT:
2466    case ATOM_DEVICE_DFP2_SUPPORT:
2467	if ((info->ChipFamily == CHIP_FAMILY_RS600) ||
2468	    (info->ChipFamily == CHIP_FAMILY_RS690) ||
2469	    (info->ChipFamily == CHIP_FAMILY_RS740))
2470	    ret = ENCODER_OBJECT_ID_INTERNAL_DDI;
2471	else if (IS_AVIVO_VARIANT)
2472	    ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
2473	else
2474	    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2475	break;
2476    case ATOM_DEVICE_DFP3_SUPPORT:
2477	ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
2478	break;
2479    }
2480
2481    return ret;
2482}
2483
2484Bool
2485RADEONGetATOMConnectorInfoFromBIOSConnectorTable (ScrnInfoPtr pScrn)
2486{
2487    RADEONInfoPtr info = RADEONPTR (pScrn);
2488    atomDataTablesPtr atomDataPtr;
2489    uint8_t crev, frev;
2490    int i, j;
2491    Bool enable_tv = FALSE;
2492
2493    if (xf86ReturnOptValBool(info->Options, OPTION_ATOM_TVOUT, FALSE))
2494	enable_tv = TRUE;
2495
2496    atomDataPtr = info->atomBIOS->atomDataPtr;
2497
2498    if (!rhdAtomGetTableRevisionAndSize(
2499	    &(atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->sHeader),
2500	    &crev,&frev,NULL)) {
2501	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Device Info Table found!\n");
2502	return FALSE;
2503    }
2504
2505    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2506	ATOM_CONNECTOR_INFO_I2C ci
2507	    = atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->asConnInfo[i];
2508
2509	if (!(le16_to_cpu(atomDataPtr->SupportedDevicesInfo
2510			  .SupportedDevicesInfo->usDeviceSupport) & (1 << i))) {
2511	    info->BiosConnector[i].valid = FALSE;
2512	    continue;
2513	}
2514
2515	/* don't support CV yet */
2516	if (i == ATOM_DEVICE_CV_INDEX) {
2517	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Skipping Component Video\n");
2518	    info->BiosConnector[i].valid = FALSE;
2519	    continue;
2520	}
2521
2522	if (!enable_tv && (i == ATOM_DEVICE_TV1_INDEX)) {
2523	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Skipping TV-Out\n");
2524	    info->BiosConnector[i].valid = FALSE;
2525	    continue;
2526	}
2527
2528	info->BiosConnector[i].valid = TRUE;
2529	info->BiosConnector[i].load_detection = TRUE;
2530	info->BiosConnector[i].shared_ddc = FALSE;
2531	info->BiosConnector[i].output_id = ci.sucI2cId.ucAccess;
2532	info->BiosConnector[i].devices = (1 << i);
2533	info->BiosConnector[i].ConnectorType = ci.sucConnectorInfo.sbfAccess.bfConnectorType;
2534
2535	if (info->BiosConnector[i].ConnectorType == CONNECTOR_NONE) {
2536	    info->BiosConnector[i].valid = FALSE;
2537	    continue;
2538	}
2539
2540	/* don't assign a gpio for tv */
2541	if ((i == ATOM_DEVICE_TV1_INDEX) ||
2542	    (i == ATOM_DEVICE_TV2_INDEX) ||
2543	    (i == ATOM_DEVICE_CV_INDEX))
2544	    info->BiosConnector[i].ddc_i2c.valid = FALSE;
2545	else
2546	    info->BiosConnector[i].ddc_i2c =
2547		RADEONLookupGPIOLineForDDC(pScrn, ci.sucI2cId.ucAccess);
2548
2549	if (!radeon_add_encoder(pScrn,
2550			   radeon_get_encoder_id_from_supported_device(pScrn, (1 << i),
2551					  ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC),
2552				(1 << i)))
2553	    return FALSE;
2554
2555	/* Always set the connector type to VGA for CRT1/CRT2. if they are
2556	 * shared with a DVI port, we'll pick up the DVI connector below when we
2557	 * merge the outputs
2558	 */
2559	if ((i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) &&
2560	    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I ||
2561	     info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D ||
2562	     info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A)) {
2563	    info->BiosConnector[i].ConnectorType = CONNECTOR_VGA;
2564	}
2565
2566	if (crev > 1) {
2567	    ATOM_CONNECTOR_INC_SRC_BITMAP isb
2568		= atomDataPtr->SupportedDevicesInfo
2569		.SupportedDevicesInfo_HD->asIntSrcInfo[i];
2570
2571	    switch (isb.ucIntSrcBitmap) {
2572		case 0x4:
2573		    info->BiosConnector[i].hpd_mask = 0x00000001;
2574		    break;
2575		case 0xa:
2576		    info->BiosConnector[i].hpd_mask = 0x00000100;
2577		    break;
2578		default:
2579		    info->BiosConnector[i].hpd_mask = 0;
2580		    break;
2581	    }
2582	} else
2583	    info->BiosConnector[i].hpd_mask = 0;
2584
2585	RADEONApplyATOMQuirks(pScrn, i);
2586
2587    }
2588
2589    /* CRTs/DFPs may share a port */
2590    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2591	if (info->BiosConnector[i].valid) {
2592	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2593		if (info->BiosConnector[j].valid && (i != j) ) {
2594		    if (info->BiosConnector[i].output_id == info->BiosConnector[j].output_id) {
2595			if (((i == ATOM_DEVICE_DFP1_INDEX) ||
2596			     (i == ATOM_DEVICE_DFP2_INDEX) ||
2597			     (i == ATOM_DEVICE_DFP3_INDEX)) &&
2598			    ((j == ATOM_DEVICE_CRT1_INDEX) ||
2599			     (j == ATOM_DEVICE_CRT2_INDEX))) {
2600			    info->BiosConnector[i].devices |= info->BiosConnector[j].devices;
2601			    if (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D)
2602				info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_I;
2603			    info->BiosConnector[j].valid = FALSE;
2604			} else if (((j == ATOM_DEVICE_DFP1_INDEX) ||
2605				    (j == ATOM_DEVICE_DFP2_INDEX) ||
2606				    (j == ATOM_DEVICE_DFP3_INDEX)) &&
2607				   ((i == ATOM_DEVICE_CRT1_INDEX) ||
2608				    (i == ATOM_DEVICE_CRT2_INDEX))) {
2609			    info->BiosConnector[j].devices |= info->BiosConnector[i].devices;
2610			    if (info->BiosConnector[j].ConnectorType == CONNECTOR_DVI_D)
2611				info->BiosConnector[j].ConnectorType = CONNECTOR_DVI_I;
2612			    info->BiosConnector[i].valid = FALSE;
2613			} else {
2614			    info->BiosConnector[i].shared_ddc = TRUE;
2615			    info->BiosConnector[j].shared_ddc = TRUE;
2616			}
2617			/* other possible combos?  */
2618		    }
2619		}
2620	    }
2621	}
2622    }
2623
2624    return TRUE;
2625}
2626
2627# ifdef ATOM_BIOS_PARSER
2628static AtomBiosResult
2629rhdAtomExec (atomBiosHandlePtr handle,
2630	     AtomBiosRequestID unused, AtomBiosArgPtr data)
2631{
2632    RADEONInfoPtr info = RADEONPTR (xf86Screens[handle->scrnIndex]);
2633    Bool ret = FALSE;
2634    char *msg;
2635    int idx = data->exec.index;
2636    void *pspace = data->exec.pspace;
2637    pointer *dataSpace = data->exec.dataSpace;
2638
2639    //RHDFUNCI(handle->scrnIndex);
2640
2641    if (dataSpace) {
2642	if (!handle->fbBase && !handle->scratchBase)
2643	    return ATOM_FAILED;
2644	if (handle->fbBase) {
2645	    if (!info->FB) {
2646		xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: "
2647			   "Cannot exec AtomBIOS: framebuffer not mapped\n",
2648			   __func__);
2649		return ATOM_FAILED;
2650	    }
2651	    *dataSpace = (uint8_t*)info->FB + handle->fbBase;
2652	} else
2653	    *dataSpace = (uint8_t*)handle->scratchBase;
2654    }
2655    ret = ParseTableWrapper(pspace, idx, handle,
2656			    handle->BIOSBase,
2657			    &msg);
2658    if (!ret)
2659	xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s\n",msg);
2660    else
2661	xf86DrvMsgVerb(handle->scrnIndex, X_INFO, 5, "%s\n",msg);
2662
2663    return (ret) ? ATOM_SUCCESS : ATOM_FAILED;
2664}
2665# endif
2666
2667AtomBiosResult
2668RHDAtomBiosFunc(int scrnIndex, atomBiosHandlePtr handle,
2669		AtomBiosRequestID id, AtomBiosArgPtr data)
2670{
2671    AtomBiosResult ret = ATOM_FAILED;
2672    int i;
2673    char *msg = NULL;
2674    enum msgDataFormat msg_f = MSG_FORMAT_NONE;
2675    AtomBiosRequestFunc req_func = NULL;
2676
2677    //RHDFUNCI(scrnIndex);
2678
2679    for (i = 0; AtomBiosRequestList[i].id != FUNC_END; i++) {
2680	if (id ==  AtomBiosRequestList[i].id) {
2681	    req_func = AtomBiosRequestList[i].request;
2682	    msg = AtomBiosRequestList[i].message;
2683	    msg_f = AtomBiosRequestList[i].message_format;
2684	    break;
2685	}
2686    }
2687
2688    if (req_func == NULL) {
2689	xf86DrvMsg(scrnIndex, X_ERROR, "Unknown AtomBIOS request: %i\n",id);
2690	return ATOM_NOT_IMPLEMENTED;
2691    }
2692    /* Hack for now */
2693    if (id == ATOMBIOS_INIT)
2694	data->val = scrnIndex;
2695
2696    if (id == ATOMBIOS_INIT || handle)
2697	ret = req_func(handle, id, data);
2698
2699    if (ret == ATOM_SUCCESS) {
2700
2701	switch (msg_f) {
2702	    case MSG_FORMAT_DEC:
2703		xf86DrvMsg(scrnIndex,X_INFO,"%s: %li\n", msg,
2704			   (unsigned long) data->val);
2705		break;
2706	    case MSG_FORMAT_HEX:
2707		xf86DrvMsg(scrnIndex,X_INFO,"%s: 0x%lx\n",msg ,
2708			   (unsigned long) data->val);
2709		break;
2710	    case MSG_FORMAT_NONE:
2711		xf86DrvMsgVerb(scrnIndex, 7, X_INFO,
2712			       "Call to %s succeeded\n", msg);
2713		break;
2714	}
2715
2716    } else {
2717
2718	char *result = (ret == ATOM_FAILED) ? "failed"
2719	    : "not implemented";
2720	switch (msg_f) {
2721	    case MSG_FORMAT_DEC:
2722	    case MSG_FORMAT_HEX:
2723		xf86DrvMsgVerb(scrnIndex, 1, X_WARNING,
2724			       "Call to %s %s\n", msg, result);
2725		break;
2726	    case MSG_FORMAT_NONE:
2727		xf86DrvMsg(scrnIndex,X_INFO,"Query for %s: %s\n", msg, result);
2728		    break;
2729	}
2730    }
2731    return ret;
2732}
2733
2734# ifdef ATOM_BIOS_PARSER
2735VOID*
2736CailAllocateMemory(VOID *CAIL,UINT16 size)
2737{
2738    void *ret;
2739    CAILFUNC(CAIL);
2740
2741    ret = malloc(size);
2742    memset(ret, 0, size);
2743    return ret;
2744}
2745
2746VOID
2747CailReleaseMemory(VOID *CAIL, VOID *addr)
2748{
2749    CAILFUNC(CAIL);
2750
2751    free(addr);
2752}
2753
2754VOID
2755CailDelayMicroSeconds(VOID *CAIL, UINT32 delay)
2756{
2757    CAILFUNC(CAIL);
2758
2759    usleep(delay);
2760
2761    /*DEBUGP(xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_INFO,"Delay %i usec\n",delay));*/
2762}
2763
2764UINT32
2765CailReadATIRegister(VOID* CAIL, UINT32 idx)
2766{
2767    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2768    RADEONInfoPtr info = RADEONPTR(pScrn);
2769    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2770    unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
2771    UINT32 ret;
2772    UINT32 mm_reg = idx << 2;
2773    CAILFUNC(CAIL);
2774
2775    if (mm_reg < info->MMIOSize)
2776	ret = INREG(mm_reg);
2777    else {
2778	OUTREG(RADEON_MM_INDEX, mm_reg);
2779	ret = INREG(RADEON_MM_DATA);
2780    }
2781
2782    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx << 2,ret));*/
2783    return ret;
2784}
2785
2786VOID
2787CailWriteATIRegister(VOID *CAIL, UINT32 idx, UINT32 data)
2788{
2789    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2790    RADEONInfoPtr info = RADEONPTR(pScrn);
2791    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2792    unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
2793    UINT32 mm_reg = idx << 2;
2794    CAILFUNC(CAIL);
2795
2796    if (mm_reg < info->MMIOSize)
2797	OUTREG(mm_reg, data);
2798    else {
2799	OUTREG(RADEON_MM_INDEX, mm_reg);
2800	OUTREG(RADEON_MM_DATA, data);
2801    }
2802
2803    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx << 2,data));*/
2804}
2805
2806UINT32
2807CailReadFBData(VOID* CAIL, UINT32 idx)
2808{
2809    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2810    RADEONInfoPtr  info   = RADEONPTR(pScrn);
2811    UINT32 ret;
2812
2813    CAILFUNC(CAIL);
2814
2815    if (((atomBiosHandlePtr)CAIL)->fbBase) {
2816	uint8_t *FBBase = (uint8_t*)info->FB;
2817	ret =  *((uint32_t*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx));
2818	/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,ret));*/
2819    } else if (((atomBiosHandlePtr)CAIL)->scratchBase) {
2820	ret = *(uint32_t*)((uint8_t*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx);
2821	/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,ret));*/
2822    } else {
2823	xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
2824		   "%s: no fbbase set\n",__func__);
2825	return 0;
2826    }
2827    return ret;
2828}
2829
2830VOID
2831CailWriteFBData(VOID *CAIL, UINT32 idx, UINT32 data)
2832{
2833    CAILFUNC(CAIL);
2834
2835    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx,data));*/
2836    if (((atomBiosHandlePtr)CAIL)->fbBase) {
2837	uint8_t *FBBase = (uint8_t*)
2838	    RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->FB;
2839	*((uint32_t*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx)) = data;
2840    } else if (((atomBiosHandlePtr)CAIL)->scratchBase) {
2841	*(uint32_t*)((uint8_t*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx) = data;
2842    } else
2843	xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
2844		   "%s: no fbbase set\n",__func__);
2845}
2846
2847ULONG
2848CailReadMC(VOID *CAIL, ULONG Address)
2849{
2850    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2851    ULONG ret;
2852
2853    CAILFUNC(CAIL);
2854
2855    ret = INMC(pScrn, Address);
2856    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,Address,ret));*/
2857    return ret;
2858}
2859
2860VOID
2861CailWriteMC(VOID *CAIL, ULONG Address, ULONG data)
2862{
2863    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2864
2865    CAILFUNC(CAIL);
2866    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,Address,data));*/
2867    OUTMC(pScrn, Address, data);
2868}
2869
2870#ifdef XSERVER_LIBPCIACCESS
2871
2872VOID
2873CailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size)
2874{
2875    pci_device_cfg_read(RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->PciInfo,
2876				ret,idx << 2 , size >> 3, NULL);
2877}
2878
2879VOID
2880CailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size)
2881{
2882    pci_device_cfg_write(RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->PciInfo,
2883			 src, idx << 2, size >> 3, NULL);
2884}
2885
2886#else
2887
2888VOID
2889CailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size)
2890{
2891    PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag;
2892
2893    CAILFUNC(CAIL);
2894
2895    switch (size) {
2896	case 8:
2897	    *(uint8_t*)ret = pciReadByte(tag,idx << 2);
2898	    break;
2899	case 16:
2900	    *(uint16_t*)ret = pciReadWord(tag,idx << 2);
2901	    break;
2902	case 32:
2903	    *(uint32_t*)ret = pciReadLong(tag,idx << 2);
2904	    break;
2905	default:
2906	xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,
2907		   X_ERROR,"%s: Unsupported size: %i\n",
2908		   __func__,(int)size);
2909	return;
2910	    break;
2911    }
2912    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,*(unsigned int*)ret));*/
2913
2914}
2915
2916VOID
2917CailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size)
2918{
2919    PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag;
2920
2921    CAILFUNC(CAIL);
2922    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx,(*(unsigned int*)src)));*/
2923    switch (size) {
2924	case 8:
2925	    pciWriteByte(tag,idx << 2,*(uint8_t*)src);
2926	    break;
2927	case 16:
2928	    pciWriteWord(tag,idx << 2,*(uint16_t*)src);
2929	    break;
2930	case 32:
2931	    pciWriteLong(tag,idx << 2,*(uint32_t*)src);
2932	    break;
2933	default:
2934	    xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
2935		       "%s: Unsupported size: %i\n",__func__,(int)size);
2936	    break;
2937    }
2938}
2939#endif
2940
2941ULONG
2942CailReadPLL(VOID *CAIL, ULONG Address)
2943{
2944    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2945    ULONG ret;
2946
2947    CAILFUNC(CAIL);
2948
2949    ret = RADEONINPLL(pScrn, Address);
2950    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,Address,ret));*/
2951    return ret;
2952}
2953
2954VOID
2955CailWritePLL(VOID *CAIL, ULONG Address,ULONG Data)
2956{
2957    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2958    CAILFUNC(CAIL);
2959
2960    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,Address,Data));*/
2961    RADEONOUTPLL(pScrn, Address, Data);
2962}
2963
2964void
2965atombios_get_command_table_version(atomBiosHandlePtr atomBIOS, int index, int *major, int *minor)
2966{
2967    ATOM_MASTER_COMMAND_TABLE *cmd_table = (void *)(atomBIOS->BIOSBase + atomBIOS->cmd_offset);
2968    ATOM_MASTER_LIST_OF_COMMAND_TABLES *table_start;
2969    ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *table_hdr;
2970
2971    //unsigned short *ptr;
2972    unsigned short offset;
2973
2974    table_start = &cmd_table->ListOfCommandTables;
2975
2976    offset  = *(((unsigned short *)table_start) + index);
2977
2978    offset = le16_to_cpu(offset);
2979    table_hdr = (ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *)(atomBIOS->BIOSBase + offset);
2980
2981    *major = table_hdr->CommonHeader.ucTableFormatRevision;
2982    *minor = table_hdr->CommonHeader.ucTableContentRevision;
2983}
2984
2985
2986UINT16 ATOM_BSWAP16(UINT16 x)
2987{
2988    return bswap_16(x);
2989}
2990
2991UINT32 ATOM_BSWAP32(UINT32 x)
2992{
2993    return bswap_32(x);
2994}
2995
2996
2997#endif /* ATOM_BIOS */
2998