radeon_atombios.c revision b13dfe66
1209ff23fSmrg/*
2209ff23fSmrg * Copyright 2007  Egbert Eich   <eich@novell.com>
3209ff23fSmrg * Copyright 2007  Luc Verhaegen <lverhaegen@novell.com>
4209ff23fSmrg * Copyright 2007  Matthias Hopf <mhopf@novell.com>
5209ff23fSmrg * Copyright 2007  Advanced Micro Devices, Inc.
6209ff23fSmrg *
7209ff23fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
8209ff23fSmrg * copy of this software and associated documentation files (the "Software"),
9209ff23fSmrg * to deal in the Software without restriction, including without limitation
10209ff23fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11209ff23fSmrg * and/or sell copies of the Software, and to permit persons to whom the
12209ff23fSmrg * Software is furnished to do so, subject to the following conditions:
13209ff23fSmrg *
14209ff23fSmrg * The above copyright notice and this permission notice shall be included in
15209ff23fSmrg * all copies or substantial portions of the Software.
16209ff23fSmrg *
17209ff23fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18209ff23fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19209ff23fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20209ff23fSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
21209ff23fSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22209ff23fSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23209ff23fSmrg * OTHER DEALINGS IN THE SOFTWARE.
24209ff23fSmrg */
25209ff23fSmrg
26209ff23fSmrg#ifdef HAVE_CONFIG_H
27209ff23fSmrg# include "config.h"
28209ff23fSmrg#endif
29209ff23fSmrg#include "xf86.h"
30209ff23fSmrg#include "xf86_OSproc.h"
31209ff23fSmrg
32209ff23fSmrg#include "radeon.h"
33ad43ddacSmrg#include "radeon_reg.h"
34209ff23fSmrg#include "radeon_atombios.h"
35209ff23fSmrg#include "radeon_atomwrapper.h"
36209ff23fSmrg#include "radeon_probe.h"
37209ff23fSmrg#include "radeon_macros.h"
38209ff23fSmrg
39209ff23fSmrg#include "ati_pciids_gen.h"
40209ff23fSmrg
41209ff23fSmrg#include "xorg-server.h"
42209ff23fSmrg
43209ff23fSmrg/* only for testing now */
44209ff23fSmrg#include "xf86DDC.h"
45209ff23fSmrg
46209ff23fSmrgtypedef AtomBiosResult (*AtomBiosRequestFunc)(atomBiosHandlePtr handle,
47209ff23fSmrg					  AtomBiosRequestID unused, AtomBiosArgPtr data);
48209ff23fSmrgtypedef struct rhdConnectorInfo *rhdConnectorInfoPtr;
49209ff23fSmrg
50209ff23fSmrgstatic AtomBiosResult rhdAtomInit(atomBiosHandlePtr unused1,
51209ff23fSmrg				      AtomBiosRequestID unused2, AtomBiosArgPtr data);
52209ff23fSmrgstatic AtomBiosResult rhdAtomTearDown(atomBiosHandlePtr handle,
53209ff23fSmrg					  AtomBiosRequestID unused1, AtomBiosArgPtr unused2);
54209ff23fSmrgstatic AtomBiosResult rhdAtomVramInfoQuery(atomBiosHandlePtr handle,
55209ff23fSmrg					       AtomBiosRequestID func, AtomBiosArgPtr data);
56209ff23fSmrgstatic AtomBiosResult rhdAtomTmdsInfoQuery(atomBiosHandlePtr handle,
57209ff23fSmrg					       AtomBiosRequestID func, AtomBiosArgPtr data);
58209ff23fSmrgstatic AtomBiosResult rhdAtomAllocateFbScratch(atomBiosHandlePtr handle,
59209ff23fSmrg						   AtomBiosRequestID func, AtomBiosArgPtr data);
60209ff23fSmrgstatic AtomBiosResult rhdAtomLvdsGetTimings(atomBiosHandlePtr handle,
61209ff23fSmrg					AtomBiosRequestID unused, AtomBiosArgPtr data);
62209ff23fSmrgstatic AtomBiosResult rhdAtomCVGetTimings(atomBiosHandlePtr handle,
63209ff23fSmrg					  AtomBiosRequestID unused, AtomBiosArgPtr data);
64209ff23fSmrgstatic AtomBiosResult rhdAtomLvdsInfoQuery(atomBiosHandlePtr handle,
65209ff23fSmrg					       AtomBiosRequestID func,  AtomBiosArgPtr data);
66209ff23fSmrgstatic AtomBiosResult rhdAtomGPIOI2CInfoQuery(atomBiosHandlePtr handle,
67209ff23fSmrg						  AtomBiosRequestID func, AtomBiosArgPtr data);
68209ff23fSmrgstatic AtomBiosResult rhdAtomFirmwareInfoQuery(atomBiosHandlePtr handle,
69209ff23fSmrg						   AtomBiosRequestID func, AtomBiosArgPtr data);
70209ff23fSmrg/*static AtomBiosResult rhdAtomConnectorInfo(atomBiosHandlePtr handle,
71209ff23fSmrg  AtomBiosRequestID unused, AtomBiosArgPtr data);*/
72209ff23fSmrg# ifdef ATOM_BIOS_PARSER
73209ff23fSmrgstatic AtomBiosResult rhdAtomExec(atomBiosHandlePtr handle,
74209ff23fSmrg				   AtomBiosRequestID unused, AtomBiosArgPtr data);
75209ff23fSmrg# endif
76209ff23fSmrgstatic AtomBiosResult
77209ff23fSmrgrhdAtomCompassionateDataQuery(atomBiosHandlePtr handle,
78209ff23fSmrg			      AtomBiosRequestID func, AtomBiosArgPtr data);
79209ff23fSmrg
80209ff23fSmrg
81b7e1c893Smrgstatic void
82b7e1c893SmrgRADEONGetATOMLVDSInfo(ScrnInfoPtr pScrn, radeon_lvds_ptr lvds);
83b7e1c893Smrg
84b7e1c893Smrg
85209ff23fSmrgenum msgDataFormat {
86209ff23fSmrg    MSG_FORMAT_NONE,
87209ff23fSmrg    MSG_FORMAT_HEX,
88209ff23fSmrg    MSG_FORMAT_DEC
89209ff23fSmrg};
90209ff23fSmrg
91209ff23fSmrgstruct atomBIOSRequests {
92209ff23fSmrg    AtomBiosRequestID id;
93209ff23fSmrg    AtomBiosRequestFunc request;
94209ff23fSmrg    char *message;
95209ff23fSmrg    enum msgDataFormat message_format;
96209ff23fSmrg} AtomBiosRequestList [] = {
97209ff23fSmrg    {ATOMBIOS_INIT,			rhdAtomInit,
98209ff23fSmrg     "AtomBIOS Init",				MSG_FORMAT_NONE},
99209ff23fSmrg    {ATOMBIOS_TEARDOWN,			rhdAtomTearDown,
100209ff23fSmrg     "AtomBIOS Teardown",			MSG_FORMAT_NONE},
101209ff23fSmrg# ifdef ATOM_BIOS_PARSER
102209ff23fSmrg    {ATOMBIOS_EXEC,			rhdAtomExec,
103209ff23fSmrg     "AtomBIOS Exec",				MSG_FORMAT_NONE},
104209ff23fSmrg#endif
105209ff23fSmrg    {ATOMBIOS_ALLOCATE_FB_SCRATCH,	rhdAtomAllocateFbScratch,
106209ff23fSmrg     "AtomBIOS Set FB Space",			MSG_FORMAT_NONE},
107209ff23fSmrg    /*{ATOMBIOS_GET_CONNECTORS,		rhdAtomConnectorInfo,
108209ff23fSmrg      "AtomBIOS Get Connectors",			MSG_FORMAT_NONE},*/
109209ff23fSmrg    {ATOMBIOS_GET_PANEL_MODE,		rhdAtomLvdsGetTimings,
110209ff23fSmrg     "AtomBIOS Get Panel Mode",			MSG_FORMAT_NONE},
111209ff23fSmrg    {ATOMBIOS_GET_PANEL_EDID,		rhdAtomLvdsGetTimings,
112209ff23fSmrg     "AtomBIOS Get Panel EDID",			MSG_FORMAT_NONE},
113209ff23fSmrg    {GET_DEFAULT_ENGINE_CLOCK,		rhdAtomFirmwareInfoQuery,
114209ff23fSmrg     "Default Engine Clock",			MSG_FORMAT_DEC},
115209ff23fSmrg    {GET_DEFAULT_MEMORY_CLOCK,		rhdAtomFirmwareInfoQuery,
116209ff23fSmrg     "Default Memory Clock",			MSG_FORMAT_DEC},
117209ff23fSmrg    {GET_MAX_PIXEL_CLOCK_PLL_OUTPUT,	rhdAtomFirmwareInfoQuery,
118209ff23fSmrg     "Maximum Pixel ClockPLL Frequency Output", MSG_FORMAT_DEC},
119209ff23fSmrg    {GET_MIN_PIXEL_CLOCK_PLL_OUTPUT,	rhdAtomFirmwareInfoQuery,
120209ff23fSmrg     "Minimum Pixel ClockPLL Frequency Output", MSG_FORMAT_DEC},
121209ff23fSmrg    {GET_MAX_PIXEL_CLOCK_PLL_INPUT,	rhdAtomFirmwareInfoQuery,
122209ff23fSmrg     "Maximum Pixel ClockPLL Frequency Input", MSG_FORMAT_DEC},
123209ff23fSmrg    {GET_MIN_PIXEL_CLOCK_PLL_INPUT,	rhdAtomFirmwareInfoQuery,
124209ff23fSmrg     "Minimum Pixel ClockPLL Frequency Input", MSG_FORMAT_DEC},
125209ff23fSmrg    {GET_MAX_PIXEL_CLK,			rhdAtomFirmwareInfoQuery,
126209ff23fSmrg     "Maximum Pixel Clock",			MSG_FORMAT_DEC},
127209ff23fSmrg    {GET_REF_CLOCK,			rhdAtomFirmwareInfoQuery,
128209ff23fSmrg     "Reference Clock",				MSG_FORMAT_DEC},
129209ff23fSmrg    {GET_FW_FB_START,			rhdAtomVramInfoQuery,
130209ff23fSmrg      "Start of VRAM area used by Firmware",	MSG_FORMAT_HEX},
131209ff23fSmrg    {GET_FW_FB_SIZE,			rhdAtomVramInfoQuery,
132209ff23fSmrg      "Framebuffer space used by Firmware (kb)", MSG_FORMAT_DEC},
133209ff23fSmrg    {ATOM_TMDS_FREQUENCY,		rhdAtomTmdsInfoQuery,
134209ff23fSmrg     "TMDS Frequency",				MSG_FORMAT_DEC},
135209ff23fSmrg    {ATOM_TMDS_PLL_CHARGE_PUMP,		rhdAtomTmdsInfoQuery,
136209ff23fSmrg     "TMDS PLL ChargePump",			MSG_FORMAT_DEC},
137209ff23fSmrg    {ATOM_TMDS_PLL_DUTY_CYCLE,		rhdAtomTmdsInfoQuery,
138209ff23fSmrg     "TMDS PLL DutyCycle",			MSG_FORMAT_DEC},
139209ff23fSmrg    {ATOM_TMDS_PLL_VCO_GAIN,		rhdAtomTmdsInfoQuery,
140209ff23fSmrg     "TMDS PLL VCO Gain",			MSG_FORMAT_DEC},
141209ff23fSmrg    {ATOM_TMDS_PLL_VOLTAGE_SWING,	rhdAtomTmdsInfoQuery,
142209ff23fSmrg     "TMDS PLL VoltageSwing",			MSG_FORMAT_DEC},
143209ff23fSmrg    {ATOM_LVDS_SUPPORTED_REFRESH_RATE,	rhdAtomLvdsInfoQuery,
144209ff23fSmrg     "LVDS Supported Refresh Rate",		MSG_FORMAT_DEC},
145209ff23fSmrg    {ATOM_LVDS_OFF_DELAY,		rhdAtomLvdsInfoQuery,
146209ff23fSmrg     "LVDS Off Delay",				MSG_FORMAT_DEC},
147209ff23fSmrg    {ATOM_LVDS_SEQ_DIG_ONTO_DE,		rhdAtomLvdsInfoQuery,
148209ff23fSmrg     "LVDS SEQ Dig onto DE",			MSG_FORMAT_DEC},
149209ff23fSmrg    {ATOM_LVDS_SEQ_DE_TO_BL,		rhdAtomLvdsInfoQuery,
150209ff23fSmrg     "LVDS SEQ DE to BL",			MSG_FORMAT_DEC},
151209ff23fSmrg    {ATOM_LVDS_DITHER,			rhdAtomLvdsInfoQuery,
152209ff23fSmrg     "LVDS Ditherc",				MSG_FORMAT_HEX},
153209ff23fSmrg    {ATOM_LVDS_DUALLINK,		rhdAtomLvdsInfoQuery,
154209ff23fSmrg     "LVDS Duallink",				MSG_FORMAT_HEX},
155209ff23fSmrg    {ATOM_LVDS_GREYLVL,			rhdAtomLvdsInfoQuery,
156209ff23fSmrg     "LVDS Grey Level",				MSG_FORMAT_HEX},
157209ff23fSmrg    {ATOM_LVDS_FPDI,			rhdAtomLvdsInfoQuery,
158209ff23fSmrg     "LVDS FPDI",				MSG_FORMAT_HEX},
159209ff23fSmrg    {ATOM_LVDS_24BIT,			rhdAtomLvdsInfoQuery,
160209ff23fSmrg     "LVDS 24Bit",				MSG_FORMAT_HEX},
161209ff23fSmrg    {ATOM_GPIO_I2C_CLK_MASK,		rhdAtomGPIOI2CInfoQuery,
162209ff23fSmrg     "GPIO_I2C_Clk_Mask",			MSG_FORMAT_HEX},
163209ff23fSmrg    {ATOM_DAC1_BG_ADJ,		rhdAtomCompassionateDataQuery,
164209ff23fSmrg     "DAC1 BG Adjustment",			MSG_FORMAT_HEX},
165209ff23fSmrg    {ATOM_DAC1_DAC_ADJ,		rhdAtomCompassionateDataQuery,
166209ff23fSmrg     "DAC1 DAC Adjustment",			MSG_FORMAT_HEX},
167209ff23fSmrg    {ATOM_DAC1_FORCE,		rhdAtomCompassionateDataQuery,
168209ff23fSmrg     "DAC1 Force Data",				MSG_FORMAT_HEX},
169209ff23fSmrg    {ATOM_DAC2_CRTC2_BG_ADJ,	rhdAtomCompassionateDataQuery,
170209ff23fSmrg     "DAC2_CRTC2 BG Adjustment",		MSG_FORMAT_HEX},
171209ff23fSmrg    {ATOM_DAC2_CRTC2_DAC_ADJ,	rhdAtomCompassionateDataQuery,
172209ff23fSmrg     "DAC2_CRTC2 DAC Adjustment",		MSG_FORMAT_HEX},
173209ff23fSmrg    {ATOM_DAC2_CRTC2_FORCE,	rhdAtomCompassionateDataQuery,
174209ff23fSmrg     "DAC2_CRTC2 Force",			MSG_FORMAT_HEX},
175209ff23fSmrg    {ATOM_DAC2_CRTC2_MUX_REG_IND,rhdAtomCompassionateDataQuery,
176209ff23fSmrg     "DAC2_CRTC2 Mux Register Index",		MSG_FORMAT_HEX},
177209ff23fSmrg    {ATOM_DAC2_CRTC2_MUX_REG_INFO,rhdAtomCompassionateDataQuery,
178209ff23fSmrg     "DAC2_CRTC2 Mux Register Info",		MSG_FORMAT_HEX},
179209ff23fSmrg    {ATOMBIOS_GET_CV_MODES,		rhdAtomCVGetTimings,
180209ff23fSmrg     "AtomBIOS Get CV Mode",			MSG_FORMAT_NONE},
181209ff23fSmrg    {FUNC_END,					NULL,
182209ff23fSmrg     NULL,					MSG_FORMAT_NONE}
183209ff23fSmrg};
184209ff23fSmrg
185209ff23fSmrgenum {
186209ff23fSmrg    legacyBIOSLocation = 0xC0000,
187209ff23fSmrg    legacyBIOSMax = 0x10000
188209ff23fSmrg};
189209ff23fSmrg
190209ff23fSmrg#define DEBUGP(x) {x;}
191209ff23fSmrg#define LOG_DEBUG 7
192209ff23fSmrg
193209ff23fSmrg#  ifdef ATOM_BIOS_PARSER
194209ff23fSmrg
195209ff23fSmrg#   define LOG_CAIL LOG_DEBUG + 1
196209ff23fSmrg
197209ff23fSmrg#if 0
198209ff23fSmrg
199209ff23fSmrgstatic void
200209ff23fSmrgRHDDebug(int scrnIndex, const char *format, ...)
201209ff23fSmrg{
202209ff23fSmrg    va_list ap;
203209ff23fSmrg
204209ff23fSmrg    va_start(ap, format);
205209ff23fSmrg    xf86VDrvMsgVerb(scrnIndex, X_INFO, LOG_DEBUG, format, ap);
206209ff23fSmrg    va_end(ap);
207209ff23fSmrg}
208209ff23fSmrg
209209ff23fSmrgstatic void
210209ff23fSmrgRHDDebugCont(const char *format, ...)
211209ff23fSmrg{
212209ff23fSmrg    va_list ap;
213209ff23fSmrg
214209ff23fSmrg    va_start(ap, format);
215209ff23fSmrg    xf86VDrvMsgVerb(-1, X_NONE, LOG_DEBUG, format, ap);
216209ff23fSmrg    va_end(ap);
217209ff23fSmrg}
218209ff23fSmrg
219209ff23fSmrg#endif
220209ff23fSmrg
221209ff23fSmrgstatic void
222209ff23fSmrgCailDebug(int scrnIndex, const char *format, ...)
223209ff23fSmrg{
224209ff23fSmrg    va_list ap;
225209ff23fSmrg
226209ff23fSmrg    va_start(ap, format);
227209ff23fSmrg    xf86VDrvMsgVerb(scrnIndex, X_INFO, LOG_CAIL, format, ap);
228209ff23fSmrg    va_end(ap);
229209ff23fSmrg}
230209ff23fSmrg#   define CAILFUNC(ptr) \
231209ff23fSmrg  CailDebug(((atomBiosHandlePtr)(ptr))->scrnIndex, "CAIL: %s\n", __func__)
232209ff23fSmrg
233209ff23fSmrg#  endif
234209ff23fSmrg
235209ff23fSmrgstatic int
236209ff23fSmrgrhdAtomAnalyzeCommonHdr(ATOM_COMMON_TABLE_HEADER *hdr)
237209ff23fSmrg{
238209ff23fSmrg    if (le16_to_cpu(hdr->usStructureSize) == 0xaa55)
239209ff23fSmrg        return FALSE;
240209ff23fSmrg
241209ff23fSmrg    return TRUE;
242209ff23fSmrg}
243209ff23fSmrg
244209ff23fSmrgstatic int
245209ff23fSmrgrhdAtomAnalyzeRomHdr(unsigned char *rombase,
246209ff23fSmrg		     ATOM_ROM_HEADER *hdr,
247209ff23fSmrg		     unsigned int *data_offset,
248209ff23fSmrg		     unsigned int *command_offset)
249209ff23fSmrg{
250209ff23fSmrg    if (!rhdAtomAnalyzeCommonHdr(&hdr->sHeader)) {
251209ff23fSmrg        return FALSE;
252209ff23fSmrg    }
253209ff23fSmrg    xf86DrvMsg(-1,X_NONE,"\tSubsystemVendorID: 0x%4.4x SubsystemID: 0x%4.4x\n",
254209ff23fSmrg               le16_to_cpu(hdr->usSubsystemVendorID),le16_to_cpu(hdr->usSubsystemID));
255209ff23fSmrg    xf86DrvMsg(-1,X_NONE,"\tIOBaseAddress: 0x%4.4x\n",le16_to_cpu(hdr->usIoBaseAddress));
256209ff23fSmrg    xf86DrvMsgVerb(-1,X_NONE,3,"\tFilename: %s\n",rombase + le16_to_cpu(hdr->usConfigFilenameOffset));
257209ff23fSmrg    xf86DrvMsgVerb(-1,X_NONE,3,"\tBIOS Bootup Message: %s\n",
258209ff23fSmrg		   rombase + le16_to_cpu(hdr->usBIOS_BootupMessageOffset));
259209ff23fSmrg
260209ff23fSmrg    *data_offset = le16_to_cpu(hdr->usMasterDataTableOffset);
261209ff23fSmrg    *command_offset = le16_to_cpu(hdr->usMasterCommandTableOffset);
262209ff23fSmrg
263209ff23fSmrg    return TRUE;
264209ff23fSmrg}
265209ff23fSmrg
266209ff23fSmrgstatic int
267209ff23fSmrgrhdAtomAnalyzeRomDataTable(unsigned char *base, uint16_t offset,
268209ff23fSmrg                    void *ptr,unsigned short *size)
269209ff23fSmrg{
270209ff23fSmrg    ATOM_COMMON_TABLE_HEADER *table = (ATOM_COMMON_TABLE_HEADER *)
271209ff23fSmrg      (base + le16_to_cpu(offset));
272209ff23fSmrg
273209ff23fSmrg   if (!*size || !rhdAtomAnalyzeCommonHdr(table)) {
274209ff23fSmrg       if (*size) *size -= 2;
275209ff23fSmrg       *(void **)ptr = NULL;
276209ff23fSmrg       return FALSE;
277209ff23fSmrg   }
278209ff23fSmrg   *size -= 2;
279209ff23fSmrg   *(void **)ptr = (void *)(table);
280209ff23fSmrg   return TRUE;
281209ff23fSmrg}
282209ff23fSmrg
283209ff23fSmrgBool
284209ff23fSmrgrhdAtomGetTableRevisionAndSize(ATOM_COMMON_TABLE_HEADER *hdr,
285209ff23fSmrg			       uint8_t *contentRev,
286209ff23fSmrg			       uint8_t *formatRev,
287209ff23fSmrg			       unsigned short *size)
288209ff23fSmrg{
289209ff23fSmrg    if (!hdr)
290209ff23fSmrg        return FALSE;
291209ff23fSmrg
292209ff23fSmrg    if (contentRev) *contentRev = hdr->ucTableContentRevision;
293209ff23fSmrg    if (formatRev) *formatRev = hdr->ucTableFormatRevision;
294209ff23fSmrg    if (size) *size = (short)le16_to_cpu(hdr->usStructureSize)
295209ff23fSmrg                   - sizeof(ATOM_COMMON_TABLE_HEADER);
296209ff23fSmrg    return TRUE;
297209ff23fSmrg}
298209ff23fSmrg
299209ff23fSmrgstatic Bool
300209ff23fSmrgrhdAtomAnalyzeMasterDataTable(unsigned char *base,
301209ff23fSmrg			      ATOM_MASTER_DATA_TABLE *table,
302209ff23fSmrg			      atomDataTablesPtr data)
303209ff23fSmrg{
304209ff23fSmrg    ATOM_MASTER_LIST_OF_DATA_TABLES *data_table =
305209ff23fSmrg        &table->ListOfDataTables;
306209ff23fSmrg    unsigned short size;
307209ff23fSmrg
308209ff23fSmrg    if (!rhdAtomAnalyzeCommonHdr(&table->sHeader))
309209ff23fSmrg        return FALSE;
310209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(&table->sHeader,NULL,NULL,
311209ff23fSmrg					&size))
312209ff23fSmrg        return FALSE;
313209ff23fSmrg# define SET_DATA_TABLE(x) {\
314209ff23fSmrg   rhdAtomAnalyzeRomDataTable(base,data_table->x,(void *)(&(data->x)),&size); \
315209ff23fSmrg    }
316209ff23fSmrg
317209ff23fSmrg# define SET_DATA_TABLE_VERS(x) {\
318209ff23fSmrg   rhdAtomAnalyzeRomDataTable(base,data_table->x,&(data->x.base),&size); \
319209ff23fSmrg    }
320209ff23fSmrg
321209ff23fSmrg    SET_DATA_TABLE(UtilityPipeLine);
322209ff23fSmrg    SET_DATA_TABLE(MultimediaCapabilityInfo);
323209ff23fSmrg    SET_DATA_TABLE(MultimediaConfigInfo);
324209ff23fSmrg    SET_DATA_TABLE(StandardVESA_Timing);
325209ff23fSmrg    SET_DATA_TABLE_VERS(FirmwareInfo);
326209ff23fSmrg    SET_DATA_TABLE(DAC_Info);
327209ff23fSmrg    SET_DATA_TABLE_VERS(LVDS_Info);
328209ff23fSmrg    SET_DATA_TABLE(TMDS_Info);
329b7e1c893Smrg    SET_DATA_TABLE_VERS(AnalogTV_Info);
330209ff23fSmrg    SET_DATA_TABLE_VERS(SupportedDevicesInfo);
331209ff23fSmrg    SET_DATA_TABLE(GPIO_I2C_Info);
332209ff23fSmrg    SET_DATA_TABLE(VRAM_UsageByFirmware);
333209ff23fSmrg    SET_DATA_TABLE(GPIO_Pin_LUT);
334209ff23fSmrg    SET_DATA_TABLE(VESA_ToInternalModeLUT);
335209ff23fSmrg    SET_DATA_TABLE_VERS(ComponentVideoInfo);
336209ff23fSmrg    SET_DATA_TABLE(PowerPlayInfo);
337209ff23fSmrg    SET_DATA_TABLE(CompassionateData);
338209ff23fSmrg    SET_DATA_TABLE(SaveRestoreInfo);
339209ff23fSmrg    SET_DATA_TABLE(PPLL_SS_Info);
340209ff23fSmrg    SET_DATA_TABLE(OemInfo);
341209ff23fSmrg    SET_DATA_TABLE(XTMDS_Info);
342209ff23fSmrg    SET_DATA_TABLE(MclkSS_Info);
343209ff23fSmrg    SET_DATA_TABLE(Object_Header);
344209ff23fSmrg    SET_DATA_TABLE(IndirectIOAccess);
345209ff23fSmrg    SET_DATA_TABLE(MC_InitParameter);
346209ff23fSmrg    SET_DATA_TABLE(ASIC_VDDC_Info);
347209ff23fSmrg    SET_DATA_TABLE(ASIC_InternalSS_Info);
348209ff23fSmrg    SET_DATA_TABLE(TV_VideoMode);
349209ff23fSmrg    SET_DATA_TABLE_VERS(VRAM_Info);
350209ff23fSmrg    SET_DATA_TABLE(MemoryTrainingInfo);
351209ff23fSmrg    SET_DATA_TABLE_VERS(IntegratedSystemInfo);
352209ff23fSmrg    SET_DATA_TABLE(ASIC_ProfilingInfo);
353209ff23fSmrg    SET_DATA_TABLE(VoltageObjectInfo);
354209ff23fSmrg    SET_DATA_TABLE(PowerSourceInfo);
355209ff23fSmrg# undef SET_DATA_TABLE
356209ff23fSmrg
357209ff23fSmrg    return TRUE;
358209ff23fSmrg}
359209ff23fSmrg
360209ff23fSmrgstatic Bool
361209ff23fSmrgrhdAtomGetDataTable(int scrnIndex,
362209ff23fSmrg		    unsigned char *base,
363209ff23fSmrg		    atomDataTables *atomDataPtr,
364209ff23fSmrg		    unsigned int *cmd_offset,
365209ff23fSmrg		    unsigned int BIOSImageSize)
366209ff23fSmrg{
367209ff23fSmrg    unsigned int data_offset;
368209ff23fSmrg    unsigned int atom_romhdr_off =  le16_to_cpu(*(unsigned short*)
369209ff23fSmrg        (base + OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER));
370209ff23fSmrg    ATOM_ROM_HEADER *atom_rom_hdr =
371209ff23fSmrg        (ATOM_ROM_HEADER *)(base + atom_romhdr_off);
372209ff23fSmrg
373209ff23fSmrg    //RHDFUNCI(scrnIndex);
374209ff23fSmrg
375209ff23fSmrg    if (atom_romhdr_off + sizeof(ATOM_ROM_HEADER) > BIOSImageSize) {
376209ff23fSmrg	xf86DrvMsg(scrnIndex,X_ERROR,
377209ff23fSmrg		   "%s: AtomROM header extends beyond BIOS image\n",__func__);
378209ff23fSmrg	return FALSE;
379209ff23fSmrg    }
380209ff23fSmrg
381209ff23fSmrg    if (memcmp("ATOM",&atom_rom_hdr->uaFirmWareSignature,4)) {
382209ff23fSmrg        xf86DrvMsg(scrnIndex,X_ERROR,"%s: No AtomBios signature found\n",
383209ff23fSmrg		   __func__);
384209ff23fSmrg        return FALSE;
385209ff23fSmrg    }
386209ff23fSmrg    xf86DrvMsg(scrnIndex, X_INFO, "ATOM BIOS Rom: \n");
387209ff23fSmrg    if (!rhdAtomAnalyzeRomHdr(base, atom_rom_hdr, &data_offset, cmd_offset)) {
388209ff23fSmrg        xf86DrvMsg(scrnIndex, X_ERROR, "RomHeader invalid\n");
389209ff23fSmrg        return FALSE;
390209ff23fSmrg    }
391209ff23fSmrg
392209ff23fSmrg    if (data_offset + sizeof (ATOM_MASTER_DATA_TABLE) > BIOSImageSize) {
393209ff23fSmrg	xf86DrvMsg(scrnIndex,X_ERROR,"%s: Atom data table outside of BIOS\n",
394209ff23fSmrg		   __func__);
395209ff23fSmrg    }
396209ff23fSmrg
397209ff23fSmrg    if (*cmd_offset + sizeof (ATOM_MASTER_COMMAND_TABLE) > BIOSImageSize) {
398209ff23fSmrg	xf86DrvMsg(scrnIndex,X_ERROR,"%s: Atom command table outside of BIOS\n",
399209ff23fSmrg		   __func__);
400209ff23fSmrg    }
401209ff23fSmrg
402209ff23fSmrg    if (!rhdAtomAnalyzeMasterDataTable(base, (ATOM_MASTER_DATA_TABLE *)
403209ff23fSmrg				       (base + data_offset),
404209ff23fSmrg				       atomDataPtr)) {
405209ff23fSmrg        xf86DrvMsg(scrnIndex, X_ERROR, "%s: ROM Master Table invalid\n",
406209ff23fSmrg		   __func__);
407209ff23fSmrg        return FALSE;
408209ff23fSmrg    }
409209ff23fSmrg    return TRUE;
410209ff23fSmrg}
411209ff23fSmrg
412209ff23fSmrgstatic Bool
413209ff23fSmrgrhdAtomGetFbBaseAndSize(atomBiosHandlePtr handle, unsigned int *base,
414209ff23fSmrg			unsigned int *size)
415209ff23fSmrg{
416209ff23fSmrg    AtomBiosArgRec data;
417209ff23fSmrg    if (RHDAtomBiosFunc(handle->scrnIndex, handle, GET_FW_FB_SIZE, &data)
418209ff23fSmrg	== ATOM_SUCCESS) {
419209ff23fSmrg	if (data.val == 0) {
420209ff23fSmrg	    xf86DrvMsg(handle->scrnIndex, X_WARNING, "%s: AtomBIOS specified VRAM "
421209ff23fSmrg		       "scratch space size invalid\n", __func__);
422209ff23fSmrg	    return FALSE;
423209ff23fSmrg	}
424209ff23fSmrg	if (size)
425209ff23fSmrg	    *size = (int)data.val;
426209ff23fSmrg    } else
427209ff23fSmrg	return FALSE;
428209ff23fSmrg    if (RHDAtomBiosFunc(handle->scrnIndex, handle, GET_FW_FB_START, &data)
429209ff23fSmrg	== ATOM_SUCCESS) {
430209ff23fSmrg	if (data.val == 0)
431209ff23fSmrg	    return FALSE;
432209ff23fSmrg	if (base)
433209ff23fSmrg	    *base = (int)data.val;
434209ff23fSmrg    }
435209ff23fSmrg    return TRUE;
436209ff23fSmrg}
437209ff23fSmrg
438209ff23fSmrg/*
439209ff23fSmrg * Uses videoRam form ScrnInfoRec.
440209ff23fSmrg */
441209ff23fSmrgstatic AtomBiosResult
442209ff23fSmrgrhdAtomAllocateFbScratch(atomBiosHandlePtr handle,
443209ff23fSmrg			 AtomBiosRequestID func, AtomBiosArgPtr data)
444209ff23fSmrg{
445209ff23fSmrg    unsigned int fb_base = 0;
446209ff23fSmrg    unsigned int fb_size = 0;
447209ff23fSmrg    unsigned int start = data->fb.start;
448209ff23fSmrg    unsigned int size = data->fb.size;
449209ff23fSmrg    handle->scratchBase = NULL;
450209ff23fSmrg    handle->fbBase = 0;
451209ff23fSmrg
452209ff23fSmrg    if (rhdAtomGetFbBaseAndSize(handle, &fb_base, &fb_size)) {
453209ff23fSmrg	xf86DrvMsg(handle->scrnIndex, X_INFO, "AtomBIOS requests %ikB"
454209ff23fSmrg		   " of VRAM scratch space\n",fb_size);
455209ff23fSmrg	fb_size *= 1024; /* convert to bytes */
456209ff23fSmrg	xf86DrvMsg(handle->scrnIndex, X_INFO, "AtomBIOS VRAM scratch base: 0x%x\n",
457209ff23fSmrg		   fb_base);
458209ff23fSmrg    } else {
459209ff23fSmrg	    fb_size = 20 * 1024;
460209ff23fSmrg	    xf86DrvMsg(handle->scrnIndex, X_INFO, " default to: %i\n",fb_size);
461209ff23fSmrg    }
462209ff23fSmrg    if (fb_base && fb_size && size) {
463209ff23fSmrg	/* 4k align */
464209ff23fSmrg	fb_size = (fb_size & ~(uint32_t)0xfff) + ((fb_size & 0xfff) ? 1 : 0);
465209ff23fSmrg	if ((fb_base + fb_size) > (start + size)) {
466209ff23fSmrg	    xf86DrvMsg(handle->scrnIndex, X_WARNING,
467209ff23fSmrg		       "%s: FW FB scratch area %i (size: %i)"
468209ff23fSmrg		       " extends beyond available framebuffer size %i\n",
469209ff23fSmrg		       __func__, fb_base, fb_size, size);
470209ff23fSmrg	} else if ((fb_base + fb_size) < (start + size)) {
471209ff23fSmrg	    xf86DrvMsg(handle->scrnIndex, X_WARNING,
472209ff23fSmrg		       "%s: FW FB scratch area not located "
473209ff23fSmrg		       "at the end of VRAM. Scratch End: "
474209ff23fSmrg		       "0x%x VRAM End: 0x%x\n", __func__,
475209ff23fSmrg		       (unsigned int)(fb_base + fb_size),
476209ff23fSmrg		       size);
477209ff23fSmrg	} else if (fb_base < start) {
478209ff23fSmrg	    xf86DrvMsg(handle->scrnIndex, X_WARNING,
479209ff23fSmrg		       "%s: FW FB scratch area extends below "
480209ff23fSmrg		       "the base of the free VRAM: 0x%x Base: 0x%x\n",
481209ff23fSmrg		       __func__, (unsigned int)(fb_base), start);
482209ff23fSmrg	} else {
483209ff23fSmrg	    size -= fb_size;
484209ff23fSmrg	    handle->fbBase = fb_base;
485209ff23fSmrg	    return ATOM_SUCCESS;
486209ff23fSmrg	}
487209ff23fSmrg    }
488209ff23fSmrg
489209ff23fSmrg    if (!handle->fbBase) {
490209ff23fSmrg	xf86DrvMsg(handle->scrnIndex, X_INFO,
491209ff23fSmrg		   "Cannot get VRAM scratch space. "
492209ff23fSmrg		   "Allocating in main memory instead\n");
4932f39173dSmrg	handle->scratchBase = calloc(fb_size,1);
494209ff23fSmrg	return ATOM_SUCCESS;
495209ff23fSmrg    }
496209ff23fSmrg    return ATOM_FAILED;
497209ff23fSmrg}
498209ff23fSmrg
499209ff23fSmrg# ifdef ATOM_BIOS_PARSER
500209ff23fSmrgBool
501209ff23fSmrgrhdAtomASICInit(atomBiosHandlePtr handle)
502209ff23fSmrg{
503209ff23fSmrg    ASIC_INIT_PS_ALLOCATION asicInit;
504209ff23fSmrg    AtomBiosArgRec data;
505209ff23fSmrg
506209ff23fSmrg    RHDAtomBiosFunc(handle->scrnIndex, handle,
507209ff23fSmrg		    GET_DEFAULT_ENGINE_CLOCK,
508209ff23fSmrg		    &data);
509b7e1c893Smrg    asicInit.sASICInitClocks.ulDefaultEngineClock = cpu_to_le32(data.val / 10);/*in 10 Khz*/
510209ff23fSmrg    RHDAtomBiosFunc(handle->scrnIndex, handle,
511209ff23fSmrg		    GET_DEFAULT_MEMORY_CLOCK,
512209ff23fSmrg		    &data);
513b7e1c893Smrg    asicInit.sASICInitClocks.ulDefaultMemoryClock = cpu_to_le32(data.val / 10);/*in 10 Khz*/
514209ff23fSmrg    data.exec.dataSpace = NULL;
515209ff23fSmrg    data.exec.index = 0x0;
516209ff23fSmrg    data.exec.pspace = &asicInit;
517209ff23fSmrg    xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling ASIC Init\n");
518209ff23fSmrg    if (RHDAtomBiosFunc(handle->scrnIndex, handle,
519209ff23fSmrg			ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
520209ff23fSmrg	xf86DrvMsg(handle->scrnIndex, X_INFO, "ASIC_INIT Successful\n");
521209ff23fSmrg	return TRUE;
522209ff23fSmrg    }
523209ff23fSmrg    xf86DrvMsg(handle->scrnIndex, X_INFO, "ASIC_INIT Failed\n");
524209ff23fSmrg    return FALSE;
525209ff23fSmrg}
526209ff23fSmrg
527209ff23fSmrgint
528ad43ddacSmrgatombios_clk_gating_setup(ScrnInfoPtr pScrn, Bool enable)
529209ff23fSmrg{
530209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
531209ff23fSmrg    DYNAMIC_CLOCK_GATING_PS_ALLOCATION dynclk_data;
532209ff23fSmrg    AtomBiosArgRec data;
533209ff23fSmrg    unsigned char *space;
534209ff23fSmrg
535209ff23fSmrg    dynclk_data.ucEnable = enable;
536209ff23fSmrg
537209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);
538209ff23fSmrg    data.exec.dataSpace = (void *)&space;
539209ff23fSmrg    data.exec.pspace = &dynclk_data;
540209ff23fSmrg
541209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
542209ff23fSmrg	ErrorF("Dynamic clock gating %s success\n", enable? "enable" : "disable");
543209ff23fSmrg	return ATOM_SUCCESS;
544209ff23fSmrg    }
545209ff23fSmrg
546209ff23fSmrg    ErrorF("Dynamic clock gating %s failure\n", enable? "enable" : "disable");
547209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
548209ff23fSmrg
549209ff23fSmrg}
550209ff23fSmrg
551209ff23fSmrgint
552ad43ddacSmrgatombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, Bool enable)
553209ff23fSmrg{
554209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
555209ff23fSmrg    ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION pwrmgt_data;
556209ff23fSmrg    AtomBiosArgRec data;
557209ff23fSmrg    unsigned char *space;
558209ff23fSmrg
559ad43ddacSmrg    /* disabling static power management causes hangs on some r4xx chips */
560ad43ddacSmrg    if (((info->ChipFamily == CHIP_FAMILY_R420) ||
561ad43ddacSmrg	 (info->ChipFamily == CHIP_FAMILY_RV410)) &&
562ad43ddacSmrg	!enable)
563ad43ddacSmrg	return ATOM_NOT_IMPLEMENTED;
564ad43ddacSmrg
565209ff23fSmrg    pwrmgt_data.ucEnable = enable;
566209ff23fSmrg
567209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableASIC_StaticPwrMgt);
568209ff23fSmrg    data.exec.dataSpace = (void *)&space;
569209ff23fSmrg    data.exec.pspace = &pwrmgt_data;
570209ff23fSmrg
571209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
572209ff23fSmrg	ErrorF("Static power management %s success\n", enable? "enable" : "disable");
573209ff23fSmrg	return ATOM_SUCCESS;
574209ff23fSmrg    }
575209ff23fSmrg
576209ff23fSmrg    ErrorF("Static power management %s failure\n", enable? "enable" : "disable");
577209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
578209ff23fSmrg
579209ff23fSmrg}
580209ff23fSmrg
581ad43ddacSmrgint
582ad43ddacSmrgatombios_set_engine_clock(ScrnInfoPtr pScrn, uint32_t engclock)
583ad43ddacSmrg{
584ad43ddacSmrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
585ad43ddacSmrg    SET_ENGINE_CLOCK_PS_ALLOCATION eng_clock_ps;
586ad43ddacSmrg    AtomBiosArgRec data;
587ad43ddacSmrg    unsigned char *space;
588ad43ddacSmrg
589ad43ddacSmrg    RADEONWaitForIdleMMIO(pScrn);
590ad43ddacSmrg
591ad43ddacSmrg    eng_clock_ps.ulTargetEngineClock = engclock; /* 10 khz */
592ad43ddacSmrg
593ad43ddacSmrg    /*ErrorF("Attempting to set engine clock to: %d\n", engclock);*/
594ad43ddacSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
595ad43ddacSmrg    data.exec.dataSpace = (void *)&space;
596ad43ddacSmrg    data.exec.pspace = &eng_clock_ps;
597ad43ddacSmrg
598ad43ddacSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
599ad43ddacSmrg	/* ErrorF("Set engine clock success\n"); */
600ad43ddacSmrg	return ATOM_SUCCESS;
601ad43ddacSmrg    }
602ad43ddacSmrg    /* ErrorF("Set engine clock failed\n"); */
603ad43ddacSmrg    return ATOM_NOT_IMPLEMENTED;
604ad43ddacSmrg}
605ad43ddacSmrg
606ad43ddacSmrgint
607ad43ddacSmrgatombios_set_memory_clock(ScrnInfoPtr pScrn, uint32_t memclock)
608ad43ddacSmrg{
609ad43ddacSmrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
610ad43ddacSmrg    SET_MEMORY_CLOCK_PS_ALLOCATION mem_clock_ps;
611ad43ddacSmrg    AtomBiosArgRec data;
612ad43ddacSmrg    unsigned char *space;
613ad43ddacSmrg
614ad43ddacSmrg    if (info->IsIGP)
615ad43ddacSmrg	return ATOM_SUCCESS;
616ad43ddacSmrg
617ad43ddacSmrg    RADEONWaitForIdleMMIO(pScrn);
618ad43ddacSmrg
619ad43ddacSmrg    mem_clock_ps.ulTargetMemoryClock = memclock; /* 10 khz */
620ad43ddacSmrg
621ad43ddacSmrg    /* ErrorF("Attempting to set mem clock to: %d\n", memclock); */
622ad43ddacSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
623ad43ddacSmrg    data.exec.dataSpace = (void *)&space;
624ad43ddacSmrg    data.exec.pspace = &mem_clock_ps;
625ad43ddacSmrg
626ad43ddacSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
627ad43ddacSmrg	/* ErrorF("Set memory clock success\n"); */
628ad43ddacSmrg	return ATOM_SUCCESS;
629ad43ddacSmrg    }
630ad43ddacSmrg    /* ErrorF("Set memory clock failed\n"); */
631ad43ddacSmrg    return ATOM_NOT_IMPLEMENTED;
632ad43ddacSmrg}
633ad43ddacSmrg
634209ff23fSmrg# endif
635209ff23fSmrg
636209ff23fSmrgstatic AtomBiosResult
637209ff23fSmrgrhdAtomInit(atomBiosHandlePtr unused1, AtomBiosRequestID unused2,
638209ff23fSmrg		    AtomBiosArgPtr data)
639209ff23fSmrg{
640209ff23fSmrg    int scrnIndex = data->val;
641209ff23fSmrg    RADEONInfoPtr  info   = RADEONPTR(xf86Screens[scrnIndex]);
642209ff23fSmrg    atomDataTablesPtr atomDataPtr;
643209ff23fSmrg    unsigned int cmd_offset;
644209ff23fSmrg    atomBiosHandlePtr handle = NULL;
645209ff23fSmrg    unsigned int BIOSImageSize = 0;
646209ff23fSmrg    data->atomhandle = NULL;
647209ff23fSmrg
648209ff23fSmrg#ifdef XSERVER_LIBPCIACCESS
649209ff23fSmrg    BIOSImageSize = info->PciInfo->rom_size > RADEON_VBIOS_SIZE ? info->PciInfo->rom_size : RADEON_VBIOS_SIZE;
650209ff23fSmrg#else
651209ff23fSmrg    BIOSImageSize = RADEON_VBIOS_SIZE;
652209ff23fSmrg#endif
653209ff23fSmrg
6542f39173dSmrg    if (!(atomDataPtr = calloc(1, sizeof(atomDataTables)))) {
655209ff23fSmrg	xf86DrvMsg(scrnIndex,X_ERROR,"Cannot allocate memory for "
656209ff23fSmrg		   "ATOM BIOS data tabes\n");
657209ff23fSmrg	goto error;
658209ff23fSmrg    }
659209ff23fSmrg    if (!rhdAtomGetDataTable(scrnIndex, info->VBIOS, atomDataPtr, &cmd_offset, BIOSImageSize))
660209ff23fSmrg	goto error1;
6612f39173dSmrg    if (!(handle = calloc(1, sizeof(atomBiosHandleRec)))) {
662209ff23fSmrg	xf86DrvMsg(scrnIndex,X_ERROR,"Cannot allocate memory\n");
663209ff23fSmrg	goto error1;
664209ff23fSmrg    }
665209ff23fSmrg    handle->BIOSBase = info->VBIOS;
666209ff23fSmrg    handle->atomDataPtr = atomDataPtr;
667209ff23fSmrg    handle->cmd_offset = cmd_offset;
668209ff23fSmrg    handle->scrnIndex = scrnIndex;
669209ff23fSmrg#if XSERVER_LIBPCIACCESS
670209ff23fSmrg    handle->device = info->PciInfo;
671209ff23fSmrg#else
672209ff23fSmrg    handle->PciTag = info->PciTag;
673209ff23fSmrg#endif
674209ff23fSmrg    handle->BIOSImageSize = BIOSImageSize;
675209ff23fSmrg
676209ff23fSmrg    data->atomhandle = handle;
677209ff23fSmrg    return ATOM_SUCCESS;
678209ff23fSmrg
679209ff23fSmrg error1:
6802f39173dSmrg    free(atomDataPtr);
681209ff23fSmrg error:
682209ff23fSmrg    return ATOM_FAILED;
683209ff23fSmrg}
684209ff23fSmrg
685209ff23fSmrgstatic AtomBiosResult
686209ff23fSmrgrhdAtomTearDown(atomBiosHandlePtr handle,
687209ff23fSmrg		AtomBiosRequestID unused1, AtomBiosArgPtr unused2)
688209ff23fSmrg{
689209ff23fSmrg    //RHDFUNC(handle);
690209ff23fSmrg
6912f39173dSmrg    free(handle->BIOSBase);
6922f39173dSmrg    free(handle->atomDataPtr);
6932f39173dSmrg    if (handle->scratchBase) free(handle->scratchBase);
6942f39173dSmrg    free(handle);
695209ff23fSmrg    return ATOM_SUCCESS;
696209ff23fSmrg}
697209ff23fSmrg
698209ff23fSmrgstatic AtomBiosResult
699209ff23fSmrgrhdAtomVramInfoQuery(atomBiosHandlePtr handle, AtomBiosRequestID func,
700209ff23fSmrg		     AtomBiosArgPtr data)
701209ff23fSmrg{
702209ff23fSmrg    atomDataTablesPtr atomDataPtr;
703209ff23fSmrg    uint32_t *val = &data->val;
704209ff23fSmrg    //RHDFUNC(handle);
705209ff23fSmrg
706209ff23fSmrg    atomDataPtr = handle->atomDataPtr;
707209ff23fSmrg
708209ff23fSmrg    switch (func) {
709209ff23fSmrg	case GET_FW_FB_START:
710b7e1c893Smrg	    if (atomDataPtr->VRAM_UsageByFirmware)
711b7e1c893Smrg		*val = le32_to_cpu(atomDataPtr->VRAM_UsageByFirmware
712b7e1c893Smrg				   ->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware);
713b7e1c893Smrg	    else
714b7e1c893Smrg		return ATOM_NOT_IMPLEMENTED;
715209ff23fSmrg	    break;
716209ff23fSmrg	case GET_FW_FB_SIZE:
717b7e1c893Smrg	    if (atomDataPtr->VRAM_UsageByFirmware)
718b7e1c893Smrg		*val =  le16_to_cpu(atomDataPtr->VRAM_UsageByFirmware
719b7e1c893Smrg				    ->asFirmwareVramReserveInfo[0].usFirmwareUseInKb);
720b7e1c893Smrg	    else
721b7e1c893Smrg		return ATOM_NOT_IMPLEMENTED;
722209ff23fSmrg	    break;
723209ff23fSmrg	default:
724209ff23fSmrg	    return ATOM_NOT_IMPLEMENTED;
725209ff23fSmrg    }
726209ff23fSmrg    return ATOM_SUCCESS;
727209ff23fSmrg}
728209ff23fSmrg
729209ff23fSmrgstatic AtomBiosResult
730209ff23fSmrgrhdAtomTmdsInfoQuery(atomBiosHandlePtr handle,
731209ff23fSmrg		     AtomBiosRequestID func, AtomBiosArgPtr data)
732209ff23fSmrg{
733209ff23fSmrg    atomDataTablesPtr atomDataPtr;
734209ff23fSmrg    uint32_t *val = &data->val;
735209ff23fSmrg    int idx = *val;
736209ff23fSmrg
737209ff23fSmrg    atomDataPtr = handle->atomDataPtr;
738209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(
739209ff23fSmrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->TMDS_Info),
740209ff23fSmrg	    NULL,NULL,NULL)) {
741209ff23fSmrg	return ATOM_FAILED;
742209ff23fSmrg    }
743209ff23fSmrg
744209ff23fSmrg    //RHDFUNC(handle);
745209ff23fSmrg
746209ff23fSmrg    switch (func) {
747209ff23fSmrg	case ATOM_TMDS_FREQUENCY:
748209ff23fSmrg	    *val = le16_to_cpu(atomDataPtr->TMDS_Info->asMiscInfo[idx].usFrequency);
749209ff23fSmrg	    break;
750209ff23fSmrg	case ATOM_TMDS_PLL_CHARGE_PUMP:
751209ff23fSmrg	    *val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_ChargePump;
752209ff23fSmrg	    break;
753209ff23fSmrg	case ATOM_TMDS_PLL_DUTY_CYCLE:
754209ff23fSmrg	    *val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_DutyCycle;
755209ff23fSmrg	    break;
756209ff23fSmrg	case ATOM_TMDS_PLL_VCO_GAIN:
757209ff23fSmrg	    *val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_VCO_Gain;
758209ff23fSmrg	    break;
759209ff23fSmrg	case ATOM_TMDS_PLL_VOLTAGE_SWING:
760209ff23fSmrg	    *val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_VoltageSwing;
761209ff23fSmrg	    break;
762209ff23fSmrg	default:
763209ff23fSmrg	    return ATOM_NOT_IMPLEMENTED;
764209ff23fSmrg    }
765209ff23fSmrg    return ATOM_SUCCESS;
766209ff23fSmrg}
767209ff23fSmrg
768209ff23fSmrgstatic DisplayModePtr
769209ff23fSmrgrhdAtomDTDTimings(atomBiosHandlePtr handle, ATOM_DTD_FORMAT *dtd)
770209ff23fSmrg{
771209ff23fSmrg    DisplayModePtr mode;
772209ff23fSmrg#define NAME_LEN 16
773209ff23fSmrg    char name[NAME_LEN];
774209ff23fSmrg
775209ff23fSmrg    //RHDFUNC(handle);
776209ff23fSmrg
777209ff23fSmrg    if (!dtd->usHActive || !dtd->usVActive)
778209ff23fSmrg	return NULL;
779209ff23fSmrg
7802f39173dSmrg    if (!(mode = (DisplayModePtr)calloc(1,sizeof(DisplayModeRec))))
781209ff23fSmrg	return NULL;
782209ff23fSmrg
783209ff23fSmrg    mode->CrtcHDisplay = mode->HDisplay = le16_to_cpu(dtd->usHActive);
784209ff23fSmrg    mode->CrtcVDisplay = mode->VDisplay = le16_to_cpu(dtd->usVActive);
785b13dfe66Smrg    mode->CrtcHBlankStart = le16_to_cpu(dtd->usHActive) + dtd->ucHBorder;
786209ff23fSmrg    mode->CrtcHBlankEnd = mode->CrtcHBlankStart + le16_to_cpu(dtd->usHBlanking_Time);
787209ff23fSmrg    mode->CrtcHTotal = mode->HTotal = mode->CrtcHBlankEnd + dtd->ucHBorder;
788b13dfe66Smrg    mode->CrtcVBlankStart = le16_to_cpu(dtd->usVActive) + dtd->ucVBorder;
789209ff23fSmrg    mode->CrtcVBlankEnd = mode->CrtcVBlankStart + le16_to_cpu(dtd->usVBlanking_Time);
790209ff23fSmrg    mode->CrtcVTotal = mode->VTotal = mode->CrtcVBlankEnd + dtd->ucVBorder;
791b13dfe66Smrg    mode->CrtcHSyncStart = mode->HSyncStart = le16_to_cpu(dtd->usHActive) + le16_to_cpu(dtd->usHSyncOffset);
792209ff23fSmrg    mode->CrtcHSyncEnd = mode->HSyncEnd = mode->HSyncStart + le16_to_cpu(dtd->usHSyncWidth);
793b13dfe66Smrg    mode->CrtcVSyncStart = mode->VSyncStart = le16_to_cpu(dtd->usVActive) + le16_to_cpu(dtd->usVSyncOffset);
794209ff23fSmrg    mode->CrtcVSyncEnd = mode->VSyncEnd = mode->VSyncStart + le16_to_cpu(dtd->usVSyncWidth);
795209ff23fSmrg
796209ff23fSmrg    mode->SynthClock = mode->Clock = le16_to_cpu(dtd->usPixClk) * 10;
797209ff23fSmrg
798209ff23fSmrg    mode->HSync = ((float) mode->Clock) / ((float)mode->HTotal);
799209ff23fSmrg    mode->VRefresh = (1000.0 * ((float) mode->Clock))
800209ff23fSmrg	/ ((float)(((float)mode->HTotal) * ((float)mode->VTotal)));
801209ff23fSmrg
802209ff23fSmrg    if (dtd->susModeMiscInfo.sbfAccess.CompositeSync)
803209ff23fSmrg	mode->Flags |= V_CSYNC;
804209ff23fSmrg    if (dtd->susModeMiscInfo.sbfAccess.Interlace)
805209ff23fSmrg	mode->Flags |= V_INTERLACE;
806209ff23fSmrg    if (dtd->susModeMiscInfo.sbfAccess.DoubleClock)
807209ff23fSmrg	mode->Flags |= V_DBLSCAN;
808209ff23fSmrg    if (dtd->susModeMiscInfo.sbfAccess.VSyncPolarity)
809209ff23fSmrg	mode->Flags |= V_NVSYNC;
810209ff23fSmrg    if (dtd->susModeMiscInfo.sbfAccess.HSyncPolarity)
811209ff23fSmrg	mode->Flags |= V_NHSYNC;
812209ff23fSmrg
813209ff23fSmrg    snprintf(name, NAME_LEN, "%dx%d",
814209ff23fSmrg	     mode->HDisplay, mode->VDisplay);
815209ff23fSmrg    mode->name = xstrdup(name);
816209ff23fSmrg
817209ff23fSmrg    ErrorF("DTD Modeline: %s  "
818209ff23fSmrg	   "%2.d  %i (%i) %i %i (%i) %i  %i (%i) %i %i (%i) %i flags: 0x%x\n",
819209ff23fSmrg	   mode->name, mode->Clock,
820209ff23fSmrg	   mode->HDisplay, mode->CrtcHBlankStart, mode->HSyncStart, mode->CrtcHSyncEnd,
821209ff23fSmrg	   mode->CrtcHBlankEnd, mode->HTotal,
822209ff23fSmrg	   mode->VDisplay, mode->CrtcVBlankStart, mode->VSyncStart, mode->VSyncEnd,
823209ff23fSmrg	   mode->CrtcVBlankEnd, mode->VTotal, mode->Flags);
824209ff23fSmrg
825209ff23fSmrg    return mode;
826209ff23fSmrg}
827209ff23fSmrg
828209ff23fSmrgstatic unsigned char*
829209ff23fSmrgrhdAtomLvdsDDC(atomBiosHandlePtr handle, uint32_t offset, unsigned char *record)
830209ff23fSmrg{
831209ff23fSmrg    unsigned char *EDIDBlock;
832209ff23fSmrg
833209ff23fSmrg    //RHDFUNC(handle);
834209ff23fSmrg
835209ff23fSmrg    while (*record != ATOM_RECORD_END_TYPE) {
836209ff23fSmrg
837209ff23fSmrg	switch (*record) {
838209ff23fSmrg	    case LCD_MODE_PATCH_RECORD_MODE_TYPE:
839209ff23fSmrg		offset += sizeof(ATOM_PATCH_RECORD_MODE);
840209ff23fSmrg		if (offset > handle->BIOSImageSize) break;
841209ff23fSmrg		record += sizeof(ATOM_PATCH_RECORD_MODE);
842209ff23fSmrg		break;
843209ff23fSmrg
844209ff23fSmrg	    case LCD_RTS_RECORD_TYPE:
845209ff23fSmrg		offset += sizeof(ATOM_LCD_RTS_RECORD);
846209ff23fSmrg		if (offset > handle->BIOSImageSize) break;
847209ff23fSmrg		record += sizeof(ATOM_LCD_RTS_RECORD);
848209ff23fSmrg		break;
849209ff23fSmrg
850209ff23fSmrg	    case LCD_CAP_RECORD_TYPE:
851209ff23fSmrg		offset += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
852209ff23fSmrg		if (offset > handle->BIOSImageSize) break;
853209ff23fSmrg		record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
854209ff23fSmrg		break;
855209ff23fSmrg
856209ff23fSmrg	    case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
857209ff23fSmrg		offset += sizeof(ATOM_FAKE_EDID_PATCH_RECORD);
858209ff23fSmrg		/* check if the structure still fully lives in the BIOS image */
859209ff23fSmrg		if (offset > handle->BIOSImageSize) break;
860209ff23fSmrg		offset += ((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDLength
861209ff23fSmrg		    - sizeof(UCHAR);
862209ff23fSmrg		if (offset > handle->BIOSImageSize) break;
863209ff23fSmrg		/* dup string as we free it later */
8642f39173dSmrg		if (!(EDIDBlock = (unsigned char *)malloc(
865209ff23fSmrg			  ((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDLength)))
866209ff23fSmrg		    return NULL;
867209ff23fSmrg		memcpy(EDIDBlock,&((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDString,
868209ff23fSmrg		       ((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDLength);
869209ff23fSmrg
870209ff23fSmrg		/* for testing */
871209ff23fSmrg		{
872209ff23fSmrg		    xf86MonPtr mon = xf86InterpretEDID(handle->scrnIndex,EDIDBlock);
873209ff23fSmrg		    xf86PrintEDID(mon);
8742f39173dSmrg		    free(mon);
875209ff23fSmrg		}
876209ff23fSmrg		return EDIDBlock;
877209ff23fSmrg
878209ff23fSmrg	    case LCD_PANEL_RESOLUTION_RECORD_TYPE:
879209ff23fSmrg		offset += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
880209ff23fSmrg		if (offset > handle->BIOSImageSize) break;
881209ff23fSmrg		record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
882209ff23fSmrg		break;
883209ff23fSmrg
884209ff23fSmrg	    default:
885209ff23fSmrg		xf86DrvMsg(handle->scrnIndex, X_ERROR,
886209ff23fSmrg			   "%s: unknown record type: %x\n",__func__,*record);
887209ff23fSmrg		return NULL;
888209ff23fSmrg	}
889209ff23fSmrg    }
890209ff23fSmrg
891209ff23fSmrg    return NULL;
892209ff23fSmrg}
893209ff23fSmrg
894209ff23fSmrgstatic AtomBiosResult
895209ff23fSmrgrhdAtomCVGetTimings(atomBiosHandlePtr handle, AtomBiosRequestID func,
896209ff23fSmrg		    AtomBiosArgPtr data)
897209ff23fSmrg{
898209ff23fSmrg    atomDataTablesPtr atomDataPtr;
899209ff23fSmrg    uint8_t crev, frev;
900209ff23fSmrg    DisplayModePtr  last       = NULL;
901209ff23fSmrg    DisplayModePtr  new        = NULL;
902209ff23fSmrg    DisplayModePtr  first      = NULL;
903209ff23fSmrg    int i;
904ad43ddacSmrg    uint16_t size;
905209ff23fSmrg
906209ff23fSmrg    data->modes = NULL;
907209ff23fSmrg
908209ff23fSmrg    atomDataPtr = handle->atomDataPtr;
909209ff23fSmrg
910209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(
911209ff23fSmrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->ComponentVideoInfo.base),
912ad43ddacSmrg	    &crev,&frev,&size)) {
913209ff23fSmrg	return ATOM_FAILED;
914209ff23fSmrg    }
915209ff23fSmrg
916209ff23fSmrg    switch (frev) {
917209ff23fSmrg	case 1:
918209ff23fSmrg	    switch (func) {
919209ff23fSmrg		case ATOMBIOS_GET_CV_MODES:
920209ff23fSmrg		    for (i = 0; i < MAX_SUPPORTED_CV_STANDARDS; i++) {
921209ff23fSmrg			new = rhdAtomDTDTimings(handle,
922209ff23fSmrg						&atomDataPtr->ComponentVideoInfo
923209ff23fSmrg						.ComponentVideoInfo->aModeTimings[i]);
924209ff23fSmrg
925209ff23fSmrg			if (!new)
926209ff23fSmrg			    continue;
927209ff23fSmrg
928209ff23fSmrg			new->type      |= M_T_DRIVER;
929209ff23fSmrg			new->next       = NULL;
930209ff23fSmrg			new->prev       = last;
931209ff23fSmrg
932209ff23fSmrg			if (last) last->next = new;
933209ff23fSmrg			last = new;
934209ff23fSmrg			if (!first) first = new;
935209ff23fSmrg		    }
936209ff23fSmrg		    if (last) {
937209ff23fSmrg			last->next   = NULL; //first;
938209ff23fSmrg			first->prev  = NULL; //last;
939209ff23fSmrg			data->modes = first;
940209ff23fSmrg		    }
941209ff23fSmrg		    if (data->modes)
942209ff23fSmrg			return ATOM_SUCCESS;
943209ff23fSmrg		default:
944209ff23fSmrg		    return ATOM_FAILED;
945209ff23fSmrg	    }
946209ff23fSmrg	case 2:
947209ff23fSmrg	    switch (func) {
948209ff23fSmrg		case ATOMBIOS_GET_CV_MODES:
949209ff23fSmrg		    for (i = 0; i < MAX_SUPPORTED_CV_STANDARDS; i++) {
950ad43ddacSmrg		        /* my rv730 table has only room for one mode */
951ad43ddacSmrg		        if ((void *)&atomDataPtr->ComponentVideoInfo.ComponentVideoInfo_v21->aModeTimings[i] -
952ad43ddacSmrg			    atomDataPtr->ComponentVideoInfo.base > size)
953ad43ddacSmrg			    break;
954ad43ddacSmrg
955209ff23fSmrg			new = rhdAtomDTDTimings(handle,
956209ff23fSmrg						&atomDataPtr->ComponentVideoInfo
957209ff23fSmrg						.ComponentVideoInfo_v21->aModeTimings[i]);
958209ff23fSmrg
959209ff23fSmrg			if (!new)
960209ff23fSmrg			    continue;
961209ff23fSmrg
962209ff23fSmrg			new->type      |= M_T_DRIVER;
963209ff23fSmrg			new->next       = NULL;
964209ff23fSmrg			new->prev       = last;
965209ff23fSmrg
966209ff23fSmrg			if (last) last->next = new;
967209ff23fSmrg			last = new;
968209ff23fSmrg			if (!first) first = new;
969209ff23fSmrg
970209ff23fSmrg		    }
971209ff23fSmrg		    if (last) {
972209ff23fSmrg			last->next   = NULL; //first;
973209ff23fSmrg			first->prev  = NULL; //last;
974209ff23fSmrg			data->modes = first;
975209ff23fSmrg		    }
976209ff23fSmrg		    if (data->modes)
977209ff23fSmrg			return ATOM_SUCCESS;
978209ff23fSmrg		    return ATOM_FAILED;
979209ff23fSmrg
980209ff23fSmrg		default:
981209ff23fSmrg		    return ATOM_FAILED;
982209ff23fSmrg	    }
983209ff23fSmrg	default:
984209ff23fSmrg	    return ATOM_NOT_IMPLEMENTED;
985209ff23fSmrg    }
986209ff23fSmrg/*NOTREACHED*/
987209ff23fSmrg}
988209ff23fSmrg
989209ff23fSmrgstatic AtomBiosResult
990209ff23fSmrgrhdAtomLvdsGetTimings(atomBiosHandlePtr handle, AtomBiosRequestID func,
991209ff23fSmrg		    AtomBiosArgPtr data)
992209ff23fSmrg{
993209ff23fSmrg    atomDataTablesPtr atomDataPtr;
994209ff23fSmrg    uint8_t crev, frev;
995209ff23fSmrg    unsigned long offset;
996209ff23fSmrg
997209ff23fSmrg    //RHDFUNC(handle);
998209ff23fSmrg
999209ff23fSmrg    atomDataPtr = handle->atomDataPtr;
1000209ff23fSmrg
1001209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(
1002209ff23fSmrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
1003209ff23fSmrg	    &frev,&crev,NULL)) {
1004209ff23fSmrg	return ATOM_FAILED;
1005209ff23fSmrg    }
1006209ff23fSmrg
1007209ff23fSmrg    switch (crev) {
1008209ff23fSmrg
1009209ff23fSmrg	case 1:
1010209ff23fSmrg	    switch (func) {
1011209ff23fSmrg		case ATOMBIOS_GET_PANEL_MODE:
1012209ff23fSmrg		    data->modes = rhdAtomDTDTimings(handle,
1013209ff23fSmrg						   &atomDataPtr->LVDS_Info
1014209ff23fSmrg						   .LVDS_Info->sLCDTiming);
1015209ff23fSmrg		    if (data->modes)
1016209ff23fSmrg			return ATOM_SUCCESS;
1017209ff23fSmrg		default:
1018209ff23fSmrg		    return ATOM_FAILED;
1019209ff23fSmrg	    }
1020209ff23fSmrg	case 2:
1021209ff23fSmrg	    switch (func) {
1022209ff23fSmrg		case ATOMBIOS_GET_PANEL_MODE:
1023209ff23fSmrg		    data->modes = rhdAtomDTDTimings(handle,
1024209ff23fSmrg						   &atomDataPtr->LVDS_Info
1025209ff23fSmrg						   .LVDS_Info_v12->sLCDTiming);
1026209ff23fSmrg		    if (data->modes)
1027209ff23fSmrg			return ATOM_SUCCESS;
1028209ff23fSmrg		    return ATOM_FAILED;
1029209ff23fSmrg
1030209ff23fSmrg		case ATOMBIOS_GET_PANEL_EDID:
1031209ff23fSmrg		    offset = (unsigned long)&atomDataPtr->LVDS_Info.base
1032209ff23fSmrg			- (unsigned long)handle->BIOSBase
1033209ff23fSmrg			+ le16_to_cpu(atomDataPtr->LVDS_Info
1034209ff23fSmrg			.LVDS_Info_v12->usExtInfoTableOffset);
1035209ff23fSmrg
1036209ff23fSmrg		    data->EDIDBlock
1037209ff23fSmrg			= rhdAtomLvdsDDC(handle, offset,
1038209ff23fSmrg					 (unsigned char *)
1039209ff23fSmrg					 &atomDataPtr->LVDS_Info.base
1040209ff23fSmrg					 + le16_to_cpu(atomDataPtr->LVDS_Info
1041209ff23fSmrg					 .LVDS_Info_v12->usExtInfoTableOffset));
1042209ff23fSmrg		    if (data->EDIDBlock)
1043209ff23fSmrg			return ATOM_SUCCESS;
1044209ff23fSmrg		default:
1045209ff23fSmrg		    return ATOM_FAILED;
1046209ff23fSmrg	    }
1047209ff23fSmrg	default:
1048209ff23fSmrg	    return ATOM_NOT_IMPLEMENTED;
1049209ff23fSmrg    }
1050209ff23fSmrg/*NOTREACHED*/
1051209ff23fSmrg}
1052209ff23fSmrg
1053209ff23fSmrgstatic AtomBiosResult
1054209ff23fSmrgrhdAtomLvdsInfoQuery(atomBiosHandlePtr handle,
1055209ff23fSmrg		     AtomBiosRequestID func,  AtomBiosArgPtr data)
1056209ff23fSmrg{
1057209ff23fSmrg    atomDataTablesPtr atomDataPtr;
1058209ff23fSmrg    uint8_t crev, frev;
1059209ff23fSmrg    uint32_t *val = &data->val;
1060209ff23fSmrg
1061209ff23fSmrg    //RHDFUNC(handle);
1062209ff23fSmrg
1063209ff23fSmrg    atomDataPtr = handle->atomDataPtr;
1064209ff23fSmrg
1065209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(
1066209ff23fSmrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
1067209ff23fSmrg	    &frev,&crev,NULL)) {
1068209ff23fSmrg	return ATOM_FAILED;
1069209ff23fSmrg    }
1070209ff23fSmrg
1071209ff23fSmrg    switch (crev) {
1072209ff23fSmrg	case 1:
1073209ff23fSmrg	    switch (func) {
1074209ff23fSmrg		case ATOM_LVDS_SUPPORTED_REFRESH_RATE:
1075209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->LVDS_Info
1076209ff23fSmrg				       .LVDS_Info->usSupportedRefreshRate);
1077209ff23fSmrg		    break;
1078209ff23fSmrg		case ATOM_LVDS_OFF_DELAY:
1079209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->LVDS_Info
1080209ff23fSmrg				       .LVDS_Info->usOffDelayInMs);
1081209ff23fSmrg		    break;
1082209ff23fSmrg		case ATOM_LVDS_SEQ_DIG_ONTO_DE:
1083209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1084209ff23fSmrg			.LVDS_Info->ucPowerSequenceDigOntoDEin10Ms * 10;
1085209ff23fSmrg		    break;
1086209ff23fSmrg		case ATOM_LVDS_SEQ_DE_TO_BL:
1087209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1088209ff23fSmrg			.LVDS_Info->ucPowerSequenceDEtoBLOnin10Ms * 10;
1089209ff23fSmrg		    break;
1090209ff23fSmrg		case     ATOM_LVDS_DITHER:
1091209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1092209ff23fSmrg			.LVDS_Info->ucLVDS_Misc & 0x40;
1093209ff23fSmrg		    break;
1094209ff23fSmrg		case     ATOM_LVDS_DUALLINK:
1095209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1096209ff23fSmrg			.LVDS_Info->ucLVDS_Misc & 0x01;
1097209ff23fSmrg		    break;
1098209ff23fSmrg		case     ATOM_LVDS_24BIT:
1099209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1100209ff23fSmrg			.LVDS_Info->ucLVDS_Misc & 0x02;
1101209ff23fSmrg		    break;
1102209ff23fSmrg		case     ATOM_LVDS_GREYLVL:
1103209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1104209ff23fSmrg			.LVDS_Info->ucLVDS_Misc & 0x0C;
1105209ff23fSmrg		    break;
1106209ff23fSmrg		case     ATOM_LVDS_FPDI:
1107209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1108209ff23fSmrg			.LVDS_Info->ucLVDS_Misc * 0x10;
1109209ff23fSmrg		    break;
1110209ff23fSmrg		default:
1111209ff23fSmrg		    return ATOM_NOT_IMPLEMENTED;
1112209ff23fSmrg	    }
1113209ff23fSmrg	    break;
1114209ff23fSmrg	case 2:
1115209ff23fSmrg	    switch (func) {
1116209ff23fSmrg		case ATOM_LVDS_SUPPORTED_REFRESH_RATE:
1117209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->LVDS_Info
1118209ff23fSmrg				       .LVDS_Info_v12->usSupportedRefreshRate);
1119209ff23fSmrg		    break;
1120209ff23fSmrg		case ATOM_LVDS_OFF_DELAY:
1121209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->LVDS_Info
1122209ff23fSmrg				       .LVDS_Info_v12->usOffDelayInMs);
1123209ff23fSmrg		    break;
1124209ff23fSmrg		case ATOM_LVDS_SEQ_DIG_ONTO_DE:
1125209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1126209ff23fSmrg			.LVDS_Info_v12->ucPowerSequenceDigOntoDEin10Ms * 10;
1127209ff23fSmrg		    break;
1128209ff23fSmrg		case ATOM_LVDS_SEQ_DE_TO_BL:
1129209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1130209ff23fSmrg			.LVDS_Info_v12->ucPowerSequenceDEtoBLOnin10Ms * 10;
1131209ff23fSmrg		    break;
1132209ff23fSmrg		case     ATOM_LVDS_DITHER:
1133209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1134209ff23fSmrg			.LVDS_Info_v12->ucLVDS_Misc & 0x40;
1135209ff23fSmrg		    break;
1136209ff23fSmrg		case     ATOM_LVDS_DUALLINK:
1137209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1138209ff23fSmrg			.LVDS_Info_v12->ucLVDS_Misc & 0x01;
1139209ff23fSmrg		    break;
1140209ff23fSmrg		case     ATOM_LVDS_24BIT:
1141209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1142209ff23fSmrg			.LVDS_Info_v12->ucLVDS_Misc & 0x02;
1143209ff23fSmrg		    break;
1144209ff23fSmrg		case     ATOM_LVDS_GREYLVL:
1145209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1146209ff23fSmrg			.LVDS_Info_v12->ucLVDS_Misc & 0x0C;
1147209ff23fSmrg		    break;
1148209ff23fSmrg		case     ATOM_LVDS_FPDI:
1149209ff23fSmrg		    *val = atomDataPtr->LVDS_Info
1150209ff23fSmrg			.LVDS_Info_v12->ucLVDS_Misc * 0x10;
1151209ff23fSmrg		    break;
1152209ff23fSmrg		default:
1153209ff23fSmrg		    return ATOM_NOT_IMPLEMENTED;
1154209ff23fSmrg	    }
1155209ff23fSmrg	    break;
1156209ff23fSmrg	default:
1157209ff23fSmrg	    return ATOM_NOT_IMPLEMENTED;
1158209ff23fSmrg    }
1159209ff23fSmrg
1160209ff23fSmrg    return ATOM_SUCCESS;
1161209ff23fSmrg}
1162209ff23fSmrg
1163209ff23fSmrgstatic AtomBiosResult
1164209ff23fSmrgrhdAtomCompassionateDataQuery(atomBiosHandlePtr handle,
1165209ff23fSmrg			AtomBiosRequestID func, AtomBiosArgPtr data)
1166209ff23fSmrg{
1167209ff23fSmrg    atomDataTablesPtr atomDataPtr;
1168209ff23fSmrg    uint8_t crev, frev;
1169209ff23fSmrg    uint32_t *val = &data->val;
1170209ff23fSmrg
1171209ff23fSmrg    //RHDFUNC(handle);
1172209ff23fSmrg
1173209ff23fSmrg    atomDataPtr = handle->atomDataPtr;
1174209ff23fSmrg
1175209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(
1176209ff23fSmrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->CompassionateData),
1177209ff23fSmrg	    &frev,&crev,NULL)) {
1178209ff23fSmrg	return ATOM_FAILED;
1179209ff23fSmrg    }
1180209ff23fSmrg
1181209ff23fSmrg    switch (func) {
1182209ff23fSmrg	case ATOM_DAC1_BG_ADJ:
1183209ff23fSmrg	    *val = atomDataPtr->CompassionateData->
1184209ff23fSmrg		ucDAC1_BG_Adjustment;
1185209ff23fSmrg	    break;
1186209ff23fSmrg	case ATOM_DAC1_DAC_ADJ:
1187209ff23fSmrg	    *val = atomDataPtr->CompassionateData->
1188209ff23fSmrg		ucDAC1_DAC_Adjustment;
1189209ff23fSmrg	    break;
1190209ff23fSmrg	case ATOM_DAC1_FORCE:
1191209ff23fSmrg	    *val = atomDataPtr->CompassionateData->
1192209ff23fSmrg		usDAC1_FORCE_Data;
1193209ff23fSmrg	    break;
1194209ff23fSmrg	case ATOM_DAC2_CRTC2_BG_ADJ:
1195209ff23fSmrg	    *val = atomDataPtr->CompassionateData->
1196209ff23fSmrg		ucDAC2_CRT2_BG_Adjustment;
1197209ff23fSmrg	    break;
1198209ff23fSmrg	case ATOM_DAC2_CRTC2_DAC_ADJ:
1199209ff23fSmrg	    *val = atomDataPtr->CompassionateData->
1200209ff23fSmrg		ucDAC2_CRT2_DAC_Adjustment;
1201209ff23fSmrg	    break;
1202209ff23fSmrg	case ATOM_DAC2_CRTC2_FORCE:
1203209ff23fSmrg	    *val = atomDataPtr->CompassionateData->
1204209ff23fSmrg		usDAC2_CRT2_FORCE_Data;
1205209ff23fSmrg	    break;
1206209ff23fSmrg	case ATOM_DAC2_CRTC2_MUX_REG_IND:
1207209ff23fSmrg	    *val = atomDataPtr->CompassionateData->
1208209ff23fSmrg		usDAC2_CRT2_MUX_RegisterIndex;
1209209ff23fSmrg	    break;
1210209ff23fSmrg	case ATOM_DAC2_CRTC2_MUX_REG_INFO:
1211209ff23fSmrg	    *val = atomDataPtr->CompassionateData->
1212209ff23fSmrg		ucDAC2_CRT2_MUX_RegisterInfo;
1213209ff23fSmrg	    break;
1214209ff23fSmrg	default:
1215209ff23fSmrg	    return ATOM_NOT_IMPLEMENTED;
1216209ff23fSmrg    }
1217209ff23fSmrg    return ATOM_SUCCESS;
1218209ff23fSmrg}
1219209ff23fSmrg
1220209ff23fSmrgstatic AtomBiosResult
1221209ff23fSmrgrhdAtomGPIOI2CInfoQuery(atomBiosHandlePtr handle,
1222209ff23fSmrg			AtomBiosRequestID func, AtomBiosArgPtr data)
1223209ff23fSmrg{
1224209ff23fSmrg    atomDataTablesPtr atomDataPtr;
1225209ff23fSmrg    uint8_t crev, frev;
1226209ff23fSmrg    uint32_t *val = &data->val;
1227209ff23fSmrg    unsigned short size;
1228209ff23fSmrg
1229209ff23fSmrg    //RHDFUNC(handle);
1230209ff23fSmrg
1231209ff23fSmrg    atomDataPtr = handle->atomDataPtr;
1232209ff23fSmrg
1233209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(
1234209ff23fSmrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->GPIO_I2C_Info),
1235209ff23fSmrg	    &frev,&crev,&size)) {
1236209ff23fSmrg	return ATOM_FAILED;
1237209ff23fSmrg    }
1238209ff23fSmrg
1239209ff23fSmrg    switch (func) {
1240209ff23fSmrg	case ATOM_GPIO_I2C_CLK_MASK:
1241209ff23fSmrg	    if ((sizeof(ATOM_COMMON_TABLE_HEADER)
1242209ff23fSmrg		 + (*val * sizeof(ATOM_GPIO_I2C_ASSIGMENT))) > size) {
1243209ff23fSmrg		xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: GPIO_I2C Device "
1244209ff23fSmrg			   "num %lu exeeds table size %u\n",__func__,
1245209ff23fSmrg			   (unsigned long)val,
1246209ff23fSmrg			   size);
1247209ff23fSmrg		return ATOM_FAILED;
1248209ff23fSmrg	    }
1249209ff23fSmrg
1250209ff23fSmrg	    *val = le16_to_cpu(atomDataPtr->GPIO_I2C_Info->asGPIO_Info[*val]
1251209ff23fSmrg			       .usClkMaskRegisterIndex);
1252209ff23fSmrg	    break;
1253209ff23fSmrg
1254209ff23fSmrg	default:
1255209ff23fSmrg	    return ATOM_NOT_IMPLEMENTED;
1256209ff23fSmrg    }
1257209ff23fSmrg    return ATOM_SUCCESS;
1258209ff23fSmrg}
1259209ff23fSmrg
1260209ff23fSmrgstatic AtomBiosResult
1261209ff23fSmrgrhdAtomFirmwareInfoQuery(atomBiosHandlePtr handle,
1262209ff23fSmrg			 AtomBiosRequestID func, AtomBiosArgPtr data)
1263209ff23fSmrg{
1264209ff23fSmrg    atomDataTablesPtr atomDataPtr;
1265209ff23fSmrg    uint8_t crev, frev;
1266209ff23fSmrg    uint32_t *val = &data->val;
1267209ff23fSmrg
1268209ff23fSmrg    //RHDFUNC(handle);
1269209ff23fSmrg
1270209ff23fSmrg    atomDataPtr = handle->atomDataPtr;
1271209ff23fSmrg
1272209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(
1273209ff23fSmrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->FirmwareInfo.base),
1274209ff23fSmrg	    &crev,&frev,NULL)) {
1275209ff23fSmrg	return ATOM_FAILED;
1276209ff23fSmrg    }
1277209ff23fSmrg
1278209ff23fSmrg    switch (crev) {
1279209ff23fSmrg	case 1:
1280209ff23fSmrg	    switch (func) {
1281209ff23fSmrg		case GET_DEFAULT_ENGINE_CLOCK:
1282209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1283209ff23fSmrg				       .FirmwareInfo->ulDefaultEngineClock) * 10;
1284209ff23fSmrg		    break;
1285209ff23fSmrg		case GET_DEFAULT_MEMORY_CLOCK:
1286209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1287209ff23fSmrg				       .FirmwareInfo->ulDefaultMemoryClock) * 10;
1288209ff23fSmrg		    break;
1289209ff23fSmrg		case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
1290209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1291209ff23fSmrg				       .FirmwareInfo->ulMaxPixelClockPLL_Output) * 10;
1292209ff23fSmrg		    break;
1293209ff23fSmrg		case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
1294209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1295209ff23fSmrg				       .FirmwareInfo->usMinPixelClockPLL_Output) * 10;
1296209ff23fSmrg		case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
1297209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1298209ff23fSmrg				       .FirmwareInfo->usMaxPixelClockPLL_Input) * 10;
1299209ff23fSmrg		    break;
1300209ff23fSmrg		case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
1301209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1302209ff23fSmrg				       .FirmwareInfo->usMinPixelClockPLL_Input) * 10;
1303209ff23fSmrg		    break;
1304209ff23fSmrg		case GET_MAX_PIXEL_CLK:
1305209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1306209ff23fSmrg				       .FirmwareInfo->usMaxPixelClock) * 10;
1307209ff23fSmrg		    break;
1308209ff23fSmrg		case GET_REF_CLOCK:
1309209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1310209ff23fSmrg				       .FirmwareInfo->usReferenceClock) * 10;
1311209ff23fSmrg		    break;
1312209ff23fSmrg		default:
1313209ff23fSmrg		    return ATOM_NOT_IMPLEMENTED;
1314209ff23fSmrg	    }
1315209ff23fSmrg	case 2:
1316209ff23fSmrg	    switch (func) {
1317209ff23fSmrg		case GET_DEFAULT_ENGINE_CLOCK:
1318209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1319209ff23fSmrg				       .FirmwareInfo_V_1_2->ulDefaultEngineClock) * 10;
1320209ff23fSmrg		    break;
1321209ff23fSmrg		case GET_DEFAULT_MEMORY_CLOCK:
1322209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1323209ff23fSmrg				       .FirmwareInfo_V_1_2->ulDefaultMemoryClock) * 10;
1324209ff23fSmrg		    break;
1325209ff23fSmrg		case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
1326209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1327209ff23fSmrg				       .FirmwareInfo_V_1_2->ulMaxPixelClockPLL_Output) * 10;
1328209ff23fSmrg		    break;
1329209ff23fSmrg		case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
1330209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1331209ff23fSmrg				       .FirmwareInfo_V_1_2->usMinPixelClockPLL_Output) * 10;
1332209ff23fSmrg		    break;
1333209ff23fSmrg		case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
1334209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1335209ff23fSmrg				       .FirmwareInfo_V_1_2->usMaxPixelClockPLL_Input) * 10;
1336209ff23fSmrg		    break;
1337209ff23fSmrg		case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
1338209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1339209ff23fSmrg				       .FirmwareInfo_V_1_2->usMinPixelClockPLL_Input) * 10;
1340209ff23fSmrg		    break;
1341209ff23fSmrg		case GET_MAX_PIXEL_CLK:
1342209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1343209ff23fSmrg				       .FirmwareInfo_V_1_2->usMaxPixelClock) * 10;
1344209ff23fSmrg		    break;
1345209ff23fSmrg		case GET_REF_CLOCK:
1346209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1347209ff23fSmrg				       .FirmwareInfo_V_1_2->usReferenceClock) * 10;
1348209ff23fSmrg		    break;
1349209ff23fSmrg		default:
1350209ff23fSmrg		    return ATOM_NOT_IMPLEMENTED;
1351209ff23fSmrg	    }
1352209ff23fSmrg	    break;
1353209ff23fSmrg	case 3:
1354209ff23fSmrg	    switch (func) {
1355209ff23fSmrg		case GET_DEFAULT_ENGINE_CLOCK:
1356209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1357209ff23fSmrg				       .FirmwareInfo_V_1_3->ulDefaultEngineClock) * 10;
1358209ff23fSmrg		    break;
1359209ff23fSmrg		case GET_DEFAULT_MEMORY_CLOCK:
1360209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1361209ff23fSmrg				       .FirmwareInfo_V_1_3->ulDefaultMemoryClock) * 10;
1362209ff23fSmrg		    break;
1363209ff23fSmrg		case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
1364209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1365209ff23fSmrg				       .FirmwareInfo_V_1_3->ulMaxPixelClockPLL_Output) * 10;
1366209ff23fSmrg		    break;
1367209ff23fSmrg		case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
1368209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1369209ff23fSmrg				       .FirmwareInfo_V_1_3->usMinPixelClockPLL_Output) * 10;
1370209ff23fSmrg		    break;
1371209ff23fSmrg		case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
1372209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1373209ff23fSmrg				       .FirmwareInfo_V_1_3->usMaxPixelClockPLL_Input) * 10;
1374209ff23fSmrg		    break;
1375209ff23fSmrg		case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
1376209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1377209ff23fSmrg				       .FirmwareInfo_V_1_3->usMinPixelClockPLL_Input) * 10;
1378209ff23fSmrg		    break;
1379209ff23fSmrg		case GET_MAX_PIXEL_CLK:
1380209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1381209ff23fSmrg				       .FirmwareInfo_V_1_3->usMaxPixelClock) * 10;
1382209ff23fSmrg		    break;
1383209ff23fSmrg		case GET_REF_CLOCK:
1384209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1385209ff23fSmrg				       .FirmwareInfo_V_1_3->usReferenceClock) * 10;
1386209ff23fSmrg		    break;
1387209ff23fSmrg		default:
1388209ff23fSmrg		    return ATOM_NOT_IMPLEMENTED;
1389209ff23fSmrg	    }
1390209ff23fSmrg	    break;
1391209ff23fSmrg	case 4:
1392209ff23fSmrg	    switch (func) {
1393209ff23fSmrg		case GET_DEFAULT_ENGINE_CLOCK:
1394209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1395209ff23fSmrg				       .FirmwareInfo_V_1_4->ulDefaultEngineClock) * 10;
1396209ff23fSmrg		    break;
1397209ff23fSmrg		case GET_DEFAULT_MEMORY_CLOCK:
1398209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1399209ff23fSmrg				       .FirmwareInfo_V_1_4->ulDefaultMemoryClock) * 10;
1400209ff23fSmrg		    break;
1401209ff23fSmrg		case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
1402209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1403209ff23fSmrg				       .FirmwareInfo_V_1_4->usMaxPixelClockPLL_Input) * 10;
1404209ff23fSmrg		    break;
1405209ff23fSmrg		case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
1406209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1407209ff23fSmrg				       .FirmwareInfo_V_1_4->usMinPixelClockPLL_Input) * 10;
1408209ff23fSmrg		    break;
1409209ff23fSmrg		case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
1410209ff23fSmrg		    *val = le32_to_cpu(atomDataPtr->FirmwareInfo
1411209ff23fSmrg				       .FirmwareInfo_V_1_4->ulMaxPixelClockPLL_Output) * 10;
1412209ff23fSmrg		    break;
1413209ff23fSmrg		case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
1414209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1415209ff23fSmrg				       .FirmwareInfo_V_1_4->usMinPixelClockPLL_Output) * 10;
1416209ff23fSmrg		    break;
1417209ff23fSmrg		case GET_MAX_PIXEL_CLK:
1418209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1419209ff23fSmrg				       .FirmwareInfo_V_1_4->usMaxPixelClock) * 10;
1420209ff23fSmrg		    break;
1421209ff23fSmrg		case GET_REF_CLOCK:
1422209ff23fSmrg		    *val = le16_to_cpu(atomDataPtr->FirmwareInfo
1423209ff23fSmrg				       .FirmwareInfo_V_1_4->usReferenceClock) * 10;
1424209ff23fSmrg		    break;
1425209ff23fSmrg		default:
1426209ff23fSmrg		    return ATOM_NOT_IMPLEMENTED;
1427209ff23fSmrg	    }
1428209ff23fSmrg	    break;
1429209ff23fSmrg	default:
1430209ff23fSmrg	    return ATOM_NOT_IMPLEMENTED;
1431209ff23fSmrg    }
1432209ff23fSmrg    return ATOM_SUCCESS;
1433209ff23fSmrg}
1434209ff23fSmrg
1435209ff23fSmrgconst int object_connector_convert[] =
1436209ff23fSmrg    { CONNECTOR_NONE,
1437209ff23fSmrg      CONNECTOR_DVI_I,
1438209ff23fSmrg      CONNECTOR_DVI_I,
1439209ff23fSmrg      CONNECTOR_DVI_D,
1440209ff23fSmrg      CONNECTOR_DVI_D,
1441209ff23fSmrg      CONNECTOR_VGA,
1442209ff23fSmrg      CONNECTOR_CTV,
1443209ff23fSmrg      CONNECTOR_STV,
1444209ff23fSmrg      CONNECTOR_NONE,
1445c503f109Smrg      CONNECTOR_NONE,
1446209ff23fSmrg      CONNECTOR_DIN,
1447209ff23fSmrg      CONNECTOR_SCART,
1448209ff23fSmrg      CONNECTOR_HDMI_TYPE_A,
1449209ff23fSmrg      CONNECTOR_HDMI_TYPE_B,
1450209ff23fSmrg      CONNECTOR_LVDS,
1451209ff23fSmrg      CONNECTOR_DIN,
1452209ff23fSmrg      CONNECTOR_NONE,
1453209ff23fSmrg      CONNECTOR_NONE,
1454209ff23fSmrg      CONNECTOR_NONE,
1455209ff23fSmrg      CONNECTOR_DISPLAY_PORT,
1456ad43ddacSmrg      CONNECTOR_EDP,
1457ad43ddacSmrg      CONNECTOR_NONE,
1458209ff23fSmrg    };
1459209ff23fSmrg
1460b7e1c893Smrgxf86MonPtr radeon_atom_get_edid(xf86OutputPtr output)
1461209ff23fSmrg{
1462b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1463b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1464b7e1c893Smrg    READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION edid_data;
1465b7e1c893Smrg    AtomBiosArgRec data;
1466b7e1c893Smrg    unsigned char *space;
1467b7e1c893Smrg    int i2c_clock = 50;
1468b7e1c893Smrg    int engine_clk = (int)info->sclk * 100;
1469b7e1c893Smrg    int prescale;
1470b7e1c893Smrg    unsigned char *edid;
1471b7e1c893Smrg    xf86MonPtr mon = NULL;
1472b7e1c893Smrg
1473b7e1c893Smrg    if (!radeon_output->ddc_i2c.hw_capable)
1474b7e1c893Smrg	return mon;
1475b7e1c893Smrg
1476b7e1c893Smrg    if (info->atomBIOS->fbBase)
1477b7e1c893Smrg	edid = (unsigned char *)info->FB + info->atomBIOS->fbBase;
1478b7e1c893Smrg    else if (info->atomBIOS->scratchBase)
1479b7e1c893Smrg	edid = (unsigned char *)info->atomBIOS->scratchBase;
1480b7e1c893Smrg    else
1481b7e1c893Smrg	return mon;
1482b7e1c893Smrg
1483b7e1c893Smrg    memset(edid, 0, ATOM_EDID_RAW_DATASIZE);
1484b7e1c893Smrg
1485b7e1c893Smrg    if (info->ChipFamily == CHIP_FAMILY_R520)
1486b7e1c893Smrg	prescale = (127 << 8) + (engine_clk * 10) / (4 * 127 * i2c_clock);
1487b7e1c893Smrg    else if (info->ChipFamily < CHIP_FAMILY_R600)
1488b7e1c893Smrg	prescale = (((engine_clk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
1489b7e1c893Smrg    else
1490b7e1c893Smrg	prescale = (info->pll.reference_freq * 10) / i2c_clock;
1491b7e1c893Smrg
1492b7e1c893Smrg    edid_data.usPrescale = prescale;
1493b7e1c893Smrg    edid_data.usVRAMAddress = 0;
1494b7e1c893Smrg    edid_data.ucSlaveAddr = 0xa0;
1495b7e1c893Smrg    edid_data.ucLineNumber = radeon_output->ddc_i2c.hw_line;
1496b7e1c893Smrg
1497b7e1c893Smrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, ReadEDIDFromHWAssistedI2C);
1498b7e1c893Smrg    data.exec.dataSpace = (void *)&space;
1499b7e1c893Smrg    data.exec.pspace = &edid_data;
1500b7e1c893Smrg
1501b7e1c893Smrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS)
1502b7e1c893Smrg	ErrorF("Atom Get EDID success\n");
1503b7e1c893Smrg    else
1504b7e1c893Smrg	ErrorF("Atom Get EDID failed\n");
1505b7e1c893Smrg
1506b7e1c893Smrg    if (edid[1] == 0xff)
1507b7e1c893Smrg	mon = xf86InterpretEDID(output->scrn->scrnIndex, edid);
1508b7e1c893Smrg
1509b7e1c893Smrg    return mon;
1510b7e1c893Smrg
1511209ff23fSmrg}
1512209ff23fSmrg
1513209ff23fSmrgstatic RADEONI2CBusRec
1514209ff23fSmrgRADEONLookupGPIOLineForDDC(ScrnInfoPtr pScrn, uint8_t id)
1515209ff23fSmrg{
1516209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1517209ff23fSmrg    atomDataTablesPtr atomDataPtr;
1518ad43ddacSmrg    ATOM_GPIO_I2C_ASSIGMENT *gpio;
1519209ff23fSmrg    RADEONI2CBusRec i2c;
1520209ff23fSmrg    uint8_t crev, frev;
1521ad43ddacSmrg    unsigned short size;
1522ad43ddacSmrg    int i, num_indices;
1523209ff23fSmrg
1524209ff23fSmrg    memset(&i2c, 0, sizeof(RADEONI2CBusRec));
1525209ff23fSmrg    i2c.valid = FALSE;
1526209ff23fSmrg
1527209ff23fSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
1528209ff23fSmrg
1529209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(
1530209ff23fSmrg	    &(atomDataPtr->GPIO_I2C_Info->sHeader),
1531ad43ddacSmrg	    &crev,&frev,&size)) {
1532209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No GPIO Info Table found!\n");
1533209ff23fSmrg	return i2c;
1534209ff23fSmrg    }
1535209ff23fSmrg
1536921a55d8Smrg    num_indices = size / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
1537ad43ddacSmrg
1538ad43ddacSmrg    for (i = 0; i < num_indices; i++) {
1539ad43ddacSmrg	    gpio = &atomDataPtr->GPIO_I2C_Info->asGPIO_Info[i];
15400974d292Smrg
15410974d292Smrg	    if (IS_DCE4_VARIANT) {
15420974d292Smrg	        if ((i == 7) &&
1543b13dfe66Smrg		    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) &&
15440974d292Smrg		    (gpio->sucI2cId.ucAccess == 0)) {
15450974d292Smrg		    gpio->sucI2cId.ucAccess = 0x97;
15460974d292Smrg		    gpio->ucDataMaskShift = 8;
15470974d292Smrg		    gpio->ucDataEnShift = 8;
15480974d292Smrg		    gpio->ucDataY_Shift = 8;
15490974d292Smrg		    gpio->ucDataA_Shift = 8;
15500974d292Smrg		}
15510974d292Smrg	    }
15520974d292Smrg
1553ad43ddacSmrg	    if (gpio->sucI2cId.ucAccess == id) {
1554ad43ddacSmrg		    i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
1555ad43ddacSmrg		    i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
1556ad43ddacSmrg		    i2c.put_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
1557ad43ddacSmrg		    i2c.put_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
1558ad43ddacSmrg		    i2c.get_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
1559ad43ddacSmrg		    i2c.get_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
1560ad43ddacSmrg		    i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
1561ad43ddacSmrg		    i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
1562ad43ddacSmrg		    i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
1563ad43ddacSmrg		    i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
1564ad43ddacSmrg		    i2c.put_clk_mask = (1 << gpio->ucClkEnShift);
1565ad43ddacSmrg		    i2c.put_data_mask = (1 << gpio->ucDataEnShift);
1566ad43ddacSmrg		    i2c.get_clk_mask = (1 << gpio->ucClkY_Shift);
1567ad43ddacSmrg		    i2c.get_data_mask = (1 <<  gpio->ucDataY_Shift);
1568ad43ddacSmrg		    i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
1569ad43ddacSmrg		    i2c.a_data_mask = (1 <<  gpio->ucDataA_Shift);
1570ad43ddacSmrg		    i2c.hw_line = gpio->sucI2cId.ucAccess;
1571ad43ddacSmrg		    i2c.hw_capable = gpio->sucI2cId.sbfAccess.bfHW_Capable;
1572ad43ddacSmrg		    i2c.valid = TRUE;
1573ad43ddacSmrg		    break;
1574ad43ddacSmrg	    }
1575ad43ddacSmrg    }
1576209ff23fSmrg
1577209ff23fSmrg#if 0
1578b7e1c893Smrg    ErrorF("id: %d\n", id);
1579ad43ddacSmrg    ErrorF("hw capable: %d\n", gpio->sucI2cId.sbfAccess.bfHW_Capable);
1580ad43ddacSmrg    ErrorF("hw engine id: %d\n", gpio->sucI2cId.sbfAccess.bfHW_EngineID);
1581ad43ddacSmrg    ErrorF("line mux %d\n", gpio->sucI2cId.sbfAccess.bfI2C_LineMux);
1582b13dfe66Smrg    ErrorF("mask_clk_reg: 0x%x\n", le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4);
1583b13dfe66Smrg    ErrorF("mask_data_reg: 0x%x\n", le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4);
1584b13dfe66Smrg    ErrorF("put_clk_reg: 0x%x\n", le16_to_cpu(gpio->usClkEnRegisterIndex) * 4);
1585b13dfe66Smrg    ErrorF("put_data_reg: 0x%x\n", le16_to_cpu(gpio->usDataEnRegisterIndex) * 4);
1586b13dfe66Smrg    ErrorF("get_clk_reg: 0x%x\n", le16_to_cpu(gpio->usClkY_RegisterIndex) * 4);
1587b13dfe66Smrg    ErrorF("get_data_reg: 0x%x\n", le16_to_cpu(gpio->usDataY_RegisterIndex) * 4);
1588b13dfe66Smrg    ErrorF("a_clk_reg: 0x%x\n", le16_to_cpu(gpio->usClkA_RegisterIndex) * 4);
1589b13dfe66Smrg    ErrorF("a_data_reg: 0x%x\n", le16_to_cpu(gpio->usDataA_RegisterIndex) * 4);
1590ad43ddacSmrg    ErrorF("mask_clk_mask: %d\n", gpio->ucClkMaskShift);
1591ad43ddacSmrg    ErrorF("mask_data_mask: %d\n", gpio->ucDataMaskShift);
1592ad43ddacSmrg    ErrorF("put_clk_mask: %d\n", gpio->ucClkEnShift);
1593ad43ddacSmrg    ErrorF("put_data_mask: %d\n", gpio->ucDataEnShift);
1594ad43ddacSmrg    ErrorF("get_clk_mask: %d\n", gpio->ucClkY_Shift);
1595ad43ddacSmrg    ErrorF("get_data_mask: %d\n", gpio->ucDataY_Shift);
1596ad43ddacSmrg    ErrorF("a_clk_mask: %d\n", gpio->ucClkA_Shift);
1597ad43ddacSmrg    ErrorF("a_data_mask: %d\n", gpio->ucDataA_Shift);
1598209ff23fSmrg#endif
1599209ff23fSmrg
1600209ff23fSmrg    return i2c;
1601209ff23fSmrg}
1602209ff23fSmrg
1603b7e1c893Smrgstatic RADEONI2CBusRec
1604b7e1c893SmrgrhdAtomParseI2CRecord(ScrnInfoPtr pScrn, atomBiosHandlePtr handle,
1605b7e1c893Smrg		      ATOM_I2C_RECORD *Record, int i)
1606b7e1c893Smrg{
1607b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1608ad43ddacSmrg    uint8_t *temp = &Record->sucI2cId;
1609b7e1c893Smrg
1610ad43ddacSmrg    info->BiosConnector[i].i2c_line_mux = *temp;
1611ad43ddacSmrg    info->BiosConnector[i].ucI2cId = *temp;
1612ad43ddacSmrg    return RADEONLookupGPIOLineForDDC(pScrn, *temp);
1613ad43ddacSmrg}
1614ad43ddacSmrg
1615ad43ddacSmrgstatic uint8_t
1616ad43ddacSmrgradeon_lookup_hpd_id(ScrnInfoPtr pScrn, ATOM_HPD_INT_RECORD *record)
1617ad43ddacSmrg{
1618ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1619ad43ddacSmrg    unsigned short size;
1620ad43ddacSmrg    uint8_t hpd = 0;
1621ad43ddacSmrg    int i, num_indices;
1622ad43ddacSmrg    struct _ATOM_GPIO_PIN_LUT *gpio_info;
1623ad43ddacSmrg    ATOM_GPIO_PIN_ASSIGNMENT *pin;
1624ad43ddacSmrg    atomDataTablesPtr atomDataPtr;
1625ad43ddacSmrg    uint8_t crev, frev;
1626ad43ddacSmrg    uint32_t reg;
1627ad43ddacSmrg
1628ad43ddacSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
1629ad43ddacSmrg
1630ad43ddacSmrg    if (!rhdAtomGetTableRevisionAndSize(
1631ad43ddacSmrg	    &(atomDataPtr->GPIO_Pin_LUT->sHeader),
1632ad43ddacSmrg	    &crev,&frev,&size)) {
1633ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No GPIO Pin Table found!\n");
1634ad43ddacSmrg	return hpd;
1635ad43ddacSmrg    }
1636ad43ddacSmrg
1637921a55d8Smrg    num_indices = size / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
1638ad43ddacSmrg
1639ad43ddacSmrg    if (IS_DCE4_VARIANT)
1640ad43ddacSmrg	reg = EVERGREEN_DC_GPIO_HPD_A;
1641ad43ddacSmrg    else
1642ad43ddacSmrg	reg = AVIVO_DC_GPIO_HPD_A;
1643ad43ddacSmrg
1644ad43ddacSmrg    gpio_info = atomDataPtr->GPIO_Pin_LUT;
1645ad43ddacSmrg    for (i = 0; i < num_indices; i++) {
1646ad43ddacSmrg	pin = &gpio_info->asGPIO_Pin[i];
1647ad43ddacSmrg	if (record->ucHPDIntGPIOID == pin->ucGPIO_ID) {
1648b13dfe66Smrg	    if ((le16_to_cpu(pin->usGpioPin_AIndex) * 4) == reg) {
1649ad43ddacSmrg		switch (pin->ucGpioPinBitShift) {
1650ad43ddacSmrg		case 0:
1651ad43ddacSmrg		default:
1652ad43ddacSmrg		    hpd = 0;
1653ad43ddacSmrg		    break;
1654ad43ddacSmrg		case 8:
1655ad43ddacSmrg		    hpd = 1;
1656ad43ddacSmrg		    break;
1657ad43ddacSmrg		case 16:
1658ad43ddacSmrg		    hpd = 2;
1659ad43ddacSmrg		    break;
1660ad43ddacSmrg		case 24:
1661ad43ddacSmrg		    hpd = 3;
1662ad43ddacSmrg		    break;
1663ad43ddacSmrg		case 26:
1664ad43ddacSmrg		    hpd = 4;
1665ad43ddacSmrg		    break;
1666ad43ddacSmrg		case 28:
1667ad43ddacSmrg		    hpd = 5;
1668ad43ddacSmrg		    break;
1669ad43ddacSmrg		}
1670ad43ddacSmrg		break;
1671ad43ddacSmrg	    }
1672ad43ddacSmrg	}
1673ad43ddacSmrg    }
1674ad43ddacSmrg
1675ad43ddacSmrg    return hpd;
1676b7e1c893Smrg}
1677b7e1c893Smrg
1678b7e1c893Smrgstatic void RADEONApplyATOMQuirks(ScrnInfoPtr pScrn, int index)
1679b7e1c893Smrg{
1680b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1681b7e1c893Smrg
1682b7e1c893Smrg    /* Asus M2A-VM HDMI board lists the DVI port as HDMI */
1683b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RS690_791E) &&
1684b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1685b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x826d)) {
1686b7e1c893Smrg	if ((info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) &&
1687b7e1c893Smrg	    (info->BiosConnector[index].devices & ATOM_DEVICE_DFP3_SUPPORT)) {
1688b7e1c893Smrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D;
1689b7e1c893Smrg	}
1690b7e1c893Smrg    }
1691c503f109Smrg
1692ad43ddacSmrg    /* RS600 board lists the DVI port as HDMI */
1693ad43ddacSmrg    if ((info->Chipset == PCI_CHIP_RS600_7941) &&
1694ad43ddacSmrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1849) &&
1695ad43ddacSmrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x7941)) {
1696ad43ddacSmrg	if ((info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) &&
1697ad43ddacSmrg	    (info->BiosConnector[index].devices & ATOM_DEVICE_DFP3_SUPPORT)) {
1698ad43ddacSmrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D;
1699ad43ddacSmrg	}
1700ad43ddacSmrg    }
1701ad43ddacSmrg
1702b7e1c893Smrg    /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
1703b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RS600_7941) &&
1704b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x147b) &&
1705b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x2412)) {
1706b7e1c893Smrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_DVI_I)
1707b7e1c893Smrg	    info->BiosConnector[index].valid = FALSE;
1708b7e1c893Smrg    }
1709b7e1c893Smrg
1710b7e1c893Smrg    /* Falcon NW laptop lists vga ddc line for LVDS */
1711b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RV410_5653) &&
1712b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1462) &&
1713b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0291)) {
1714b7e1c893Smrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_LVDS) {
1715b7e1c893Smrg	    info->BiosConnector[index].ddc_i2c.valid = FALSE;
1716b7e1c893Smrg	}
1717b7e1c893Smrg    }
1718b7e1c893Smrg
1719b7e1c893Smrg    /* Funky macbooks */
1720b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RV530_71C5) &&
1721b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) &&
1722b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) {
1723b7e1c893Smrg	if ((index == ATOM_DEVICE_CRT1_INDEX) ||
1724b7e1c893Smrg	    (index == ATOM_DEVICE_CRT2_INDEX) ||
1725b7e1c893Smrg	    (index == ATOM_DEVICE_DFP2_INDEX))
1726b7e1c893Smrg	    info->BiosConnector[index].valid = FALSE;
1727b7e1c893Smrg
1728b7e1c893Smrg	if (index == ATOM_DEVICE_DFP1_INDEX) {
1729b7e1c893Smrg	    info->BiosConnector[index].devices |= ATOM_DEVICE_CRT2_SUPPORT;
1730b7e1c893Smrg	}
1731b7e1c893Smrg    }
1732b7e1c893Smrg
1733b7e1c893Smrg    /* ASUS HD 3600 XT board lists the DVI port as HDMI */
1734b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RV635_9598) &&
1735b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1736b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01da)) {
1737ad43ddacSmrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A)
1738ad43ddacSmrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_I;
1739b7e1c893Smrg    }
1740b7e1c893Smrg
1741c503f109Smrg    /* ASUS HD 3450 board lists the DVI port as HDMI */
1742c503f109Smrg    if ((info->Chipset == PCI_CHIP_RV620_95C5) &&
1743c503f109Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1744c503f109Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01e2)) {
1745ad43ddacSmrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A)
1746ad43ddacSmrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_I;
1747c503f109Smrg    }
1748c503f109Smrg
1749c503f109Smrg    /* some BIOSes seem to report DAC on HDMI - usually this is a board with
1750c503f109Smrg     * HDMI + VGA reporting as HDMI
1751c503f109Smrg     */
1752ad43ddacSmrg    if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) {
1753c503f109Smrg	if (info->BiosConnector[index].devices & (ATOM_DEVICE_CRT_SUPPORT)) {
1754c503f109Smrg	    info->BiosConnector[index].devices &= ~(ATOM_DEVICE_DFP_SUPPORT);
1755c503f109Smrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_VGA;
1756c503f109Smrg	    info->BiosConnector[index].connector_object = 0;
1757ad43ddacSmrg	}
1758c503f109Smrg    }
1759b7e1c893Smrg
1760b7e1c893Smrg}
1761b7e1c893Smrg
1762b7e1c893Smrguint32_t
1763b7e1c893Smrgradeon_get_device_index(uint32_t device_support)
1764b7e1c893Smrg{
1765b7e1c893Smrg    uint32_t device_index = 0;
1766b7e1c893Smrg
1767b7e1c893Smrg    if (device_support == 0)
1768b7e1c893Smrg	return 0;
1769b7e1c893Smrg
1770b7e1c893Smrg    while ((device_support & 1) == 0) {
1771b7e1c893Smrg	device_support >>= 1;
1772b7e1c893Smrg	device_index++;
1773b7e1c893Smrg    }
1774b7e1c893Smrg    return device_index;
1775b7e1c893Smrg}
1776b7e1c893Smrg
1777b7e1c893Smrgradeon_encoder_ptr
1778b7e1c893Smrgradeon_get_encoder(xf86OutputPtr output)
1779b7e1c893Smrg{
1780b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1781b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR(output->scrn);
1782b7e1c893Smrg
1783b7e1c893Smrg    if (radeon_output->active_device)
1784b7e1c893Smrg	return info->encoders[radeon_get_device_index(radeon_output->active_device)];
1785b7e1c893Smrg    else
1786b7e1c893Smrg	return NULL;
1787b7e1c893Smrg}
1788b7e1c893Smrg
1789b7e1c893SmrgBool
1790b7e1c893Smrgradeon_add_encoder(ScrnInfoPtr pScrn, uint32_t encoder_id, uint32_t device_support)
1791b7e1c893Smrg{
1792b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1793b7e1c893Smrg    uint32_t device_index = radeon_get_device_index(device_support);
1794b7e1c893Smrg    int i;
1795b7e1c893Smrg
1796b7e1c893Smrg    if (device_support == 0) {
1797b7e1c893Smrg	ErrorF("device support == 0\n");
1798b7e1c893Smrg	return FALSE;
1799b7e1c893Smrg    }
1800b7e1c893Smrg
1801b7e1c893Smrg    if (info->encoders[device_index] != NULL)
1802b7e1c893Smrg	return TRUE;
1803b7e1c893Smrg    else {
1804b7e1c893Smrg	/* look for the encoder */
1805b7e1c893Smrg	for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
1806b7e1c893Smrg	    if ((info->encoders[i] != NULL) && (info->encoders[i]->encoder_id == encoder_id)) {
1807b7e1c893Smrg		info->encoders[device_index] = info->encoders[i];
1808b7e1c893Smrg		switch (encoder_id) {
1809b7e1c893Smrg		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1810b7e1c893Smrg		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1811b7e1c893Smrg		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1812b7e1c893Smrg		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1813b7e1c893Smrg		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1814b7e1c893Smrg		    if (device_support & ATOM_DEVICE_LCD1_SUPPORT) {
1815b7e1c893Smrg			if (info->encoders[device_index]->dev_priv == NULL) {
1816b7e1c893Smrg			    info->encoders[device_index]->dev_priv =
18172f39173dSmrg				(radeon_lvds_ptr)calloc(1,sizeof(radeon_lvds_rec));
1818b7e1c893Smrg			    if (info->encoders[device_index]->dev_priv == NULL) {
18192f39173dSmrg				ErrorF("calloc failed\n");
1820b7e1c893Smrg				return FALSE;
1821b7e1c893Smrg			    } else
1822b7e1c893Smrg				RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1823b7e1c893Smrg			}
1824b7e1c893Smrg		    }
1825b7e1c893Smrg		    break;
1826b7e1c893Smrg		}
1827b7e1c893Smrg		return TRUE;
1828b7e1c893Smrg	    }
1829b7e1c893Smrg	}
1830b7e1c893Smrg
18312f39173dSmrg	info->encoders[device_index] = (radeon_encoder_ptr)calloc(1,sizeof(radeon_encoder_rec));
1832b7e1c893Smrg	if (info->encoders[device_index] != NULL) {
1833b7e1c893Smrg	    info->encoders[device_index]->encoder_id = encoder_id;
1834b7e1c893Smrg	    info->encoders[device_index]->devices = 0;
1835b7e1c893Smrg	    info->encoders[device_index]->dev_priv = NULL;
1836b7e1c893Smrg	    // add dev_priv stuff
1837b7e1c893Smrg	    switch (encoder_id) {
1838b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
18392f39173dSmrg		    info->encoders[device_index]->dev_priv = (radeon_lvds_ptr)calloc(1,sizeof(radeon_lvds_rec));
1840b7e1c893Smrg		    if (info->encoders[device_index]->dev_priv == NULL) {
18412f39173dSmrg			ErrorF("calloc failed\n");
1842b7e1c893Smrg			return FALSE;
1843b7e1c893Smrg		    } else {
1844b7e1c893Smrg			if (info->IsAtomBios)
1845b7e1c893Smrg			    RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1846b7e1c893Smrg			else
1847b7e1c893Smrg			    RADEONGetLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1848b7e1c893Smrg		    }
1849b7e1c893Smrg		break;
1850b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1851b7e1c893Smrg		if (!IS_AVIVO_VARIANT) {
18522f39173dSmrg		    info->encoders[device_index]->dev_priv = (radeon_tvdac_ptr)calloc(1,sizeof(radeon_tvdac_rec));
1853b7e1c893Smrg		    if (info->encoders[device_index]->dev_priv == NULL) {
18542f39173dSmrg			ErrorF("calloc failed\n");
1855b7e1c893Smrg			return FALSE;
1856b7e1c893Smrg		    } else
1857b7e1c893Smrg			RADEONGetTVDacAdjInfo(pScrn, (radeon_tvdac_ptr)info->encoders[device_index]->dev_priv);
1858b7e1c893Smrg		}
1859b7e1c893Smrg		break;
1860b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1861b7e1c893Smrg		if (!IS_AVIVO_VARIANT) {
18622f39173dSmrg		    info->encoders[device_index]->dev_priv = (radeon_tmds_ptr)calloc(1,sizeof(radeon_tmds_rec));
1863b7e1c893Smrg		    if (info->encoders[device_index]->dev_priv == NULL) {
18642f39173dSmrg			ErrorF("calloc failed\n");
1865b7e1c893Smrg			return FALSE;
1866b7e1c893Smrg		    } else
1867b7e1c893Smrg			RADEONGetTMDSInfo(pScrn, (radeon_tmds_ptr)info->encoders[device_index]->dev_priv);
1868b7e1c893Smrg		}
1869b7e1c893Smrg		break;
1870b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1871b7e1c893Smrg		if (!IS_AVIVO_VARIANT) {
18722f39173dSmrg		    info->encoders[device_index]->dev_priv = (radeon_dvo_ptr)calloc(1,sizeof(radeon_dvo_rec));
1873b7e1c893Smrg		    if (info->encoders[device_index]->dev_priv == NULL) {
18742f39173dSmrg			ErrorF("calloc failed\n");
1875b7e1c893Smrg			return FALSE;
1876b7e1c893Smrg		    } else
1877b7e1c893Smrg			RADEONGetExtTMDSInfo(pScrn, (radeon_dvo_ptr)info->encoders[device_index]->dev_priv);
1878b7e1c893Smrg		}
1879b7e1c893Smrg		break;
1880b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1881b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1882b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1883b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1884b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1885b7e1c893Smrg		if (device_support & ATOM_DEVICE_LCD1_SUPPORT) {
18862f39173dSmrg		    info->encoders[device_index]->dev_priv = (radeon_lvds_ptr)calloc(1,sizeof(radeon_lvds_rec));
1887b7e1c893Smrg		    if (info->encoders[device_index]->dev_priv == NULL) {
18882f39173dSmrg			ErrorF("calloc failed\n");
1889b7e1c893Smrg			return FALSE;
1890b7e1c893Smrg		    } else
1891b7e1c893Smrg			RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1892b7e1c893Smrg		}
1893b7e1c893Smrg		break;
1894b7e1c893Smrg	    }
1895b7e1c893Smrg	    return TRUE;
1896b7e1c893Smrg	} else {
18972f39173dSmrg	    ErrorF("calloc failed\n");
1898b7e1c893Smrg	    return FALSE;
1899b7e1c893Smrg	}
1900b7e1c893Smrg    }
1901b7e1c893Smrg
1902b7e1c893Smrg}
1903b7e1c893Smrg
1904209ff23fSmrgBool
1905209ff23fSmrgRADEONGetATOMConnectorInfoFromBIOSObject (ScrnInfoPtr pScrn)
1906209ff23fSmrg{
1907209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1908209ff23fSmrg    uint8_t crev, frev;
1909209ff23fSmrg    unsigned short size;
1910209ff23fSmrg    atomDataTablesPtr atomDataPtr;
1911209ff23fSmrg    ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
1912b7e1c893Smrg    ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
1913209ff23fSmrg    ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj = NULL;
1914b7e1c893Smrg    int i, j, path_size, device_support;
1915b7e1c893Smrg    Bool enable_tv = FALSE;
1916b7e1c893Smrg
1917b7e1c893Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_ATOM_TVOUT, FALSE))
1918b7e1c893Smrg	enable_tv = TRUE;
1919209ff23fSmrg
1920209ff23fSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
1921209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->Object_Header), &crev, &frev, &size))
1922209ff23fSmrg	return FALSE;
1923209ff23fSmrg
1924209ff23fSmrg    if (crev < 2)
1925209ff23fSmrg	return FALSE;
1926209ff23fSmrg
1927b7e1c893Smrg    path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
1928b7e1c893Smrg	((char *)&atomDataPtr->Object_Header->sHeader +
1929b7e1c893Smrg	 le16_to_cpu(atomDataPtr->Object_Header->usDisplayPathTableOffset));
1930209ff23fSmrg    con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
1931209ff23fSmrg	((char *)&atomDataPtr->Object_Header->sHeader +
1932209ff23fSmrg	 le16_to_cpu(atomDataPtr->Object_Header->usConnectorObjectTableOffset));
1933b7e1c893Smrg    device_support = le16_to_cpu(atomDataPtr->Object_Header->usDeviceSupport);
1934b7e1c893Smrg
1935b7e1c893Smrg    path_size = 0;
1936b7e1c893Smrg    for (i = 0; i < path_obj->ucNumOfDispPath; i++) {
1937b7e1c893Smrg	uint8_t *addr = (uint8_t *)path_obj->asDispPath;
1938b7e1c893Smrg	ATOM_DISPLAY_OBJECT_PATH *path;
1939b7e1c893Smrg	addr += path_size;
1940b7e1c893Smrg	path = (ATOM_DISPLAY_OBJECT_PATH *)addr;
1941c503f109Smrg	path_size += le16_to_cpu(path->usSize);
1942b7e1c893Smrg
1943c503f109Smrg	if (device_support & le16_to_cpu(path->usDeviceTag)) {
1944b7e1c893Smrg	    uint8_t con_obj_id, con_obj_num, con_obj_type;
1945b7e1c893Smrg
1946c503f109Smrg	    con_obj_id = (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
1947c503f109Smrg	    con_obj_num = (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
1948c503f109Smrg	    con_obj_type = (le16_to_cpu(path->usConnObjectId) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
1949b7e1c893Smrg
1950c503f109Smrg	    if ((le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_TV1_SUPPORT) ||
1951c503f109Smrg		(le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_TV2_SUPPORT)) {
1952b7e1c893Smrg		if (!enable_tv) {
1953b7e1c893Smrg		    info->BiosConnector[i].valid = FALSE;
1954b7e1c893Smrg		    continue;
1955b7e1c893Smrg		}
1956b7e1c893Smrg	    }
1957209ff23fSmrg
1958b7e1c893Smrg	    /* don't support CV yet */
1959c503f109Smrg	    if (le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_CV_SUPPORT) {
1960b7e1c893Smrg		info->BiosConnector[i].valid = FALSE;
1961b7e1c893Smrg		continue;
1962b7e1c893Smrg	    }
1963209ff23fSmrg
1964b7e1c893Smrg	    if (info->IsIGP &&
1965b7e1c893Smrg		(con_obj_id == CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) {
1966b7e1c893Smrg		uint32_t slot_config, ct;
1967209ff23fSmrg
1968b7e1c893Smrg		igp_obj = info->atomBIOS->atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2;
1969209ff23fSmrg
1970b7e1c893Smrg		if (!igp_obj)
1971b7e1c893Smrg		    info->BiosConnector[i].ConnectorType = object_connector_convert[con_obj_id];
1972b7e1c893Smrg		else {
1973b7e1c893Smrg		    if (con_obj_num == 1)
1974b7e1c893Smrg			slot_config = igp_obj->ulDDISlot1Config;
1975b7e1c893Smrg		    else
1976b7e1c893Smrg			slot_config = igp_obj->ulDDISlot2Config;
1977209ff23fSmrg
1978b7e1c893Smrg		    ct = (slot_config  >> 16) & 0xff;
1979b7e1c893Smrg		    info->BiosConnector[i].ConnectorType = object_connector_convert[ct];
1980ad43ddacSmrg		    info->BiosConnector[i].connector_object_id = ct;
1981b7e1c893Smrg		    info->BiosConnector[i].igp_lane_info = slot_config & 0xffff;
1982b7e1c893Smrg		}
1983ad43ddacSmrg	    } else {
1984b7e1c893Smrg		info->BiosConnector[i].ConnectorType = object_connector_convert[con_obj_id];
1985ad43ddacSmrg		info->BiosConnector[i].connector_object_id = con_obj_id;
1986ad43ddacSmrg	    }
1987b7e1c893Smrg
1988b7e1c893Smrg	    if (info->BiosConnector[i].ConnectorType == CONNECTOR_NONE) {
1989b7e1c893Smrg		info->BiosConnector[i].valid = FALSE;
1990b7e1c893Smrg		continue;
1991b7e1c893Smrg	    } else
1992b7e1c893Smrg		info->BiosConnector[i].valid = TRUE;
1993c503f109Smrg	    info->BiosConnector[i].devices = le16_to_cpu(path->usDeviceTag);
1994c503f109Smrg	    info->BiosConnector[i].connector_object = le16_to_cpu(path->usConnObjectId);
1995b7e1c893Smrg
1996c503f109Smrg	    for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
1997b7e1c893Smrg		uint8_t enc_obj_id, enc_obj_num, enc_obj_type;
1998b7e1c893Smrg
1999c503f109Smrg		enc_obj_id = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
2000c503f109Smrg		enc_obj_num = (le16_to_cpu(path->usGraphicObjIds[j]) & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
2001c503f109Smrg		enc_obj_type = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
2002b7e1c893Smrg
2003b7e1c893Smrg		if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
2004b7e1c893Smrg		    if (enc_obj_num == 2)
2005b7e1c893Smrg			info->BiosConnector[i].linkb = TRUE;
2006b7e1c893Smrg		    else
2007b7e1c893Smrg			info->BiosConnector[i].linkb = FALSE;
2008b7e1c893Smrg
2009c503f109Smrg		    if (!radeon_add_encoder(pScrn, enc_obj_id, le16_to_cpu(path->usDeviceTag)))
2010b7e1c893Smrg			return FALSE;
2011b7e1c893Smrg		}
2012209ff23fSmrg	    }
2013209ff23fSmrg
2014b7e1c893Smrg	    /* look up gpio for ddc */
2015c503f109Smrg	    if ((le16_to_cpu(path->usDeviceTag) & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
2016b7e1c893Smrg		for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
2017c503f109Smrg		    if (le16_to_cpu(path->usConnObjectId) == le16_to_cpu(con_obj->asObjects[j].usObjectID)) {
2018b7e1c893Smrg			ATOM_COMMON_RECORD_HEADER *Record = (ATOM_COMMON_RECORD_HEADER *)
2019b7e1c893Smrg			    ((char *)&atomDataPtr->Object_Header->sHeader
2020b7e1c893Smrg			     + le16_to_cpu(con_obj->asObjects[j].usRecordOffset));
2021b7e1c893Smrg
2022b7e1c893Smrg			while (Record->ucRecordType > 0
2023b7e1c893Smrg			       && Record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER ) {
2024b7e1c893Smrg
2025b7e1c893Smrg			    /*ErrorF("record type %d\n", Record->ucRecordType);*/
2026b7e1c893Smrg			    switch (Record->ucRecordType) {
2027b7e1c893Smrg			    case ATOM_I2C_RECORD_TYPE:
2028b7e1c893Smrg				info->BiosConnector[i].ddc_i2c =
2029b7e1c893Smrg				    rhdAtomParseI2CRecord(pScrn, info->atomBIOS,
2030b7e1c893Smrg							  (ATOM_I2C_RECORD *)Record, j);
2031b7e1c893Smrg				break;
2032b7e1c893Smrg			    case ATOM_HPD_INT_RECORD_TYPE:
2033ad43ddacSmrg				info->BiosConnector[i].hpd_id =
2034ad43ddacSmrg				    radeon_lookup_hpd_id(pScrn,
2035ad43ddacSmrg							 (ATOM_HPD_INT_RECORD *)Record);
2036b7e1c893Smrg				break;
2037b7e1c893Smrg			    case ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE:
2038b7e1c893Smrg				break;
2039b7e1c893Smrg			    }
2040b7e1c893Smrg
2041b7e1c893Smrg			    Record = (ATOM_COMMON_RECORD_HEADER*)
2042b7e1c893Smrg				((char *)Record + Record->ucRecordSize);
2043b7e1c893Smrg			}
2044b7e1c893Smrg			break;
2045b7e1c893Smrg		    }
2046b7e1c893Smrg		}
2047b7e1c893Smrg	    }
2048b7e1c893Smrg	}
2049b7e1c893Smrg	RADEONApplyATOMQuirks(pScrn, i);
2050b7e1c893Smrg    }
2051209ff23fSmrg
2052b7e1c893Smrg    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2053b7e1c893Smrg	if (info->BiosConnector[i].valid) {
2054b7e1c893Smrg	    /* shared connectors */
2055b7e1c893Smrg	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2056b7e1c893Smrg		if (info->BiosConnector[j].valid && (i != j) ) {
2057b7e1c893Smrg		    if (info->BiosConnector[i].connector_object == info->BiosConnector[j].connector_object) {
2058b7e1c893Smrg			info->BiosConnector[i].devices |= info->BiosConnector[j].devices;
2059b7e1c893Smrg			info->BiosConnector[j].valid = FALSE;
2060b7e1c893Smrg		    }
2061b7e1c893Smrg		}
2062b7e1c893Smrg	    }
2063b7e1c893Smrg	    /* shared ddc */
2064b7e1c893Smrg	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2065b7e1c893Smrg		if (info->BiosConnector[j].valid && (i != j) ) {
2066b7e1c893Smrg		    if (info->BiosConnector[i].i2c_line_mux == info->BiosConnector[j].i2c_line_mux) {
2067b7e1c893Smrg			info->BiosConnector[i].shared_ddc = TRUE;
2068b7e1c893Smrg			info->BiosConnector[j].shared_ddc = TRUE;
2069b7e1c893Smrg		    }
2070b7e1c893Smrg		}
2071209ff23fSmrg	    }
2072209ff23fSmrg	}
2073b7e1c893Smrg    }
2074209ff23fSmrg
2075b7e1c893Smrg    return TRUE;
2076b7e1c893Smrg}
2077209ff23fSmrg
2078b7e1c893Smrgstatic void
2079b7e1c893SmrgRADEONGetATOMLVDSInfo(ScrnInfoPtr pScrn, radeon_lvds_ptr lvds)
2080b7e1c893Smrg{
2081b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2082b7e1c893Smrg    radeon_native_mode_ptr native_mode = &lvds->native_mode;
2083b7e1c893Smrg    atomDataTablesPtr atomDataPtr;
2084b7e1c893Smrg    uint8_t crev, frev;
2085ad43ddacSmrg    uint16_t misc;
2086209ff23fSmrg
2087b7e1c893Smrg    atomDataPtr = info->atomBIOS->atomDataPtr;
2088209ff23fSmrg
2089b7e1c893Smrg    if (!rhdAtomGetTableRevisionAndSize(
2090b7e1c893Smrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
2091b7e1c893Smrg	    &frev,&crev,NULL)) {
2092b7e1c893Smrg	return;
2093b7e1c893Smrg    }
2094209ff23fSmrg
2095b7e1c893Smrg    switch (crev) {
2096b7e1c893Smrg    case 1:
2097b7e1c893Smrg	native_mode->PanelXRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHActive);
2098b7e1c893Smrg	native_mode->PanelYRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVActive);
2099b7e1c893Smrg	native_mode->DotClock   = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usPixClk) * 10;
2100b7e1c893Smrg	native_mode->HBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHBlanking_Time);
2101b7e1c893Smrg	native_mode->HOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHSyncOffset);
2102b7e1c893Smrg	native_mode->HSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHSyncWidth);
2103b7e1c893Smrg	native_mode->VBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVBlanking_Time);
2104b7e1c893Smrg	native_mode->VOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVSyncOffset);
2105b7e1c893Smrg	native_mode->VSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVSyncWidth);
2106ad43ddacSmrg	misc = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.susModeMiscInfo.usAccess);
2107ad43ddacSmrg	if (misc & ATOM_VSYNC_POLARITY)
2108ad43ddacSmrg	    native_mode->Flags |= V_NVSYNC;
2109ad43ddacSmrg	if (misc & ATOM_HSYNC_POLARITY)
2110ad43ddacSmrg	    native_mode->Flags |= V_NHSYNC;
2111ad43ddacSmrg	if (misc & ATOM_COMPOSITESYNC)
2112ad43ddacSmrg	    native_mode->Flags |= V_CSYNC;
2113ad43ddacSmrg	if (misc & ATOM_INTERLACE)
2114ad43ddacSmrg	    native_mode->Flags |= V_INTERLACE;
2115ad43ddacSmrg	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2116ad43ddacSmrg	    native_mode->Flags |= V_DBLSCAN;
2117b7e1c893Smrg	lvds->PanelPwrDly = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->usOffDelayInMs);
2118b7e1c893Smrg	lvds->lvds_misc   =  atomDataPtr->LVDS_Info.LVDS_Info->ucLVDS_Misc;
2119b7e1c893Smrg	lvds->lvds_ss_id  =  atomDataPtr->LVDS_Info.LVDS_Info->ucSS_Id;
2120b7e1c893Smrg	break;
2121b7e1c893Smrg    case 2:
2122b7e1c893Smrg	native_mode->PanelXRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHActive);
2123b7e1c893Smrg	native_mode->PanelYRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVActive);
2124b7e1c893Smrg	native_mode->DotClock   = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usPixClk) * 10;
2125b7e1c893Smrg	native_mode->HBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHBlanking_Time);
2126b7e1c893Smrg	native_mode->HOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHSyncOffset);
2127b7e1c893Smrg	native_mode->HSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHSyncWidth);
2128b7e1c893Smrg	native_mode->VBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVBlanking_Time);
2129b7e1c893Smrg	native_mode->VOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVSyncOffset);
2130b7e1c893Smrg	native_mode->VSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVSyncWidth);
2131ad43ddacSmrg	misc = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.susModeMiscInfo.usAccess);
2132ad43ddacSmrg	if (misc & ATOM_VSYNC_POLARITY)
2133ad43ddacSmrg	    native_mode->Flags |= V_NVSYNC;
2134ad43ddacSmrg	if (misc & ATOM_HSYNC_POLARITY)
2135ad43ddacSmrg	    native_mode->Flags |= V_NHSYNC;
2136ad43ddacSmrg	if (misc & ATOM_COMPOSITESYNC)
2137ad43ddacSmrg	    native_mode->Flags |= V_CSYNC;
2138ad43ddacSmrg	if (misc & ATOM_INTERLACE)
2139ad43ddacSmrg	    native_mode->Flags |= V_INTERLACE;
2140ad43ddacSmrg	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2141ad43ddacSmrg	    native_mode->Flags |= V_DBLSCAN;
2142b7e1c893Smrg	lvds->PanelPwrDly = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->usOffDelayInMs);
2143b7e1c893Smrg	lvds->lvds_misc   =  atomDataPtr->LVDS_Info.LVDS_Info_v12->ucLVDS_Misc;
2144b7e1c893Smrg	lvds->lvds_ss_id  =  atomDataPtr->LVDS_Info.LVDS_Info_v12->ucSS_Id;
2145b7e1c893Smrg	break;
2146209ff23fSmrg    }
2147b7e1c893Smrg    native_mode->Flags = 0;
2148b7e1c893Smrg
2149b7e1c893Smrg    if (lvds->PanelPwrDly > 2000 || lvds->PanelPwrDly < 0)
2150b7e1c893Smrg	lvds->PanelPwrDly = 2000;
2151b7e1c893Smrg
2152b7e1c893Smrg    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2153b7e1c893Smrg	       "LVDS Info:\n"
2154b7e1c893Smrg	       "XRes: %d, YRes: %d, DotClock: %d\n"
2155b7e1c893Smrg	       "HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n"
2156b7e1c893Smrg	       "VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n",
2157b7e1c893Smrg	       native_mode->PanelXRes, native_mode->PanelYRes, native_mode->DotClock,
2158b7e1c893Smrg	       native_mode->HBlank, native_mode->HOverPlus, native_mode->HSyncWidth,
2159b7e1c893Smrg	       native_mode->VBlank, native_mode->VOverPlus, native_mode->VSyncWidth);
2160209ff23fSmrg}
2161209ff23fSmrg
2162ad43ddacSmrgvoid
2163ad43ddacSmrgRADEONATOMGetIGPInfo(ScrnInfoPtr pScrn)
2164ad43ddacSmrg{
2165ad43ddacSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2166ad43ddacSmrg    atomDataTablesPtr atomDataPtr;
2167ad43ddacSmrg    unsigned short size;
2168ad43ddacSmrg    uint8_t crev, frev;
2169ad43ddacSmrg
2170ad43ddacSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
2171ad43ddacSmrg
2172ad43ddacSmrg    if (!rhdAtomGetTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->IntegratedSystemInfo.base), &frev, &crev, &size))
2173ad43ddacSmrg	return;
2174ad43ddacSmrg
2175ad43ddacSmrg    switch (crev) {
2176ad43ddacSmrg    case 1:
2177ad43ddacSmrg	info->igp_sideport_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->ulBootUpMemoryClock / 100.0;
2178ad43ddacSmrg	info->igp_system_mclk = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usK8MemoryClock);
2179ad43ddacSmrg	info->igp_ht_link_clk = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usFSBClock);
2180ad43ddacSmrg	info->igp_ht_link_width = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->ucHTLinkWidth;
2181ad43ddacSmrg	break;
2182ad43ddacSmrg    case 2:
2183ad43ddacSmrg	info->igp_sideport_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulBootUpSidePortClock / 100.0;
2184ad43ddacSmrg	info->igp_system_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulBootUpUMAClock / 100.0;
2185ad43ddacSmrg	info->igp_ht_link_clk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulHTLinkFreq / 100.0;
2186ad43ddacSmrg	info->igp_ht_link_width = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->usMinHTLinkWidth);
2187ad43ddacSmrg	break;
2188ad43ddacSmrg    }
2189ad43ddacSmrg}
2190ad43ddacSmrg
2191209ff23fSmrgBool
2192209ff23fSmrgRADEONGetATOMTVInfo(xf86OutputPtr output)
2193209ff23fSmrg{
2194209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
2195209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2196209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2197b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
2198209ff23fSmrg    ATOM_ANALOG_TV_INFO *tv_info;
2199209ff23fSmrg
2200b7e1c893Smrg    tv_info = info->atomBIOS->atomDataPtr->AnalogTV_Info.AnalogTV_Info;
2201209ff23fSmrg
2202209ff23fSmrg    if (!tv_info)
2203209ff23fSmrg	return FALSE;
2204209ff23fSmrg
2205209ff23fSmrg    switch(tv_info->ucTV_BootUpDefaultStandard) {
2206209ff23fSmrg    case NTSCJ_SUPPORT:
2207b7e1c893Smrg	tvout->default_tvStd = TV_STD_NTSC_J;
2208209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC-J\n");
2209209ff23fSmrg	break;
2210209ff23fSmrg    case PAL_SUPPORT:
2211b7e1c893Smrg	tvout->default_tvStd = TV_STD_PAL;
2212209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL\n");
2213209ff23fSmrg	break;
2214209ff23fSmrg    case PALM_SUPPORT:
2215b7e1c893Smrg	tvout->default_tvStd = TV_STD_PAL_M;
2216209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-M\n");
2217209ff23fSmrg	break;
2218209ff23fSmrg    case PAL60_SUPPORT:
2219b7e1c893Smrg	tvout->default_tvStd = TV_STD_PAL_60;
2220209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-60\n");
2221209ff23fSmrg	break;
2222b7e1c893Smrg    default:
2223b7e1c893Smrg    case NTSC_SUPPORT:
2224b7e1c893Smrg	tvout->default_tvStd = TV_STD_NTSC;
2225b7e1c893Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC\n");
2226b7e1c893Smrg	break;
2227209ff23fSmrg    }
2228209ff23fSmrg
2229b7e1c893Smrg    tvout->tvStd = tvout->default_tvStd;
2230209ff23fSmrg
2231209ff23fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standards supported by chip: ");
2232b7e1c893Smrg    tvout->SupportedTVStds = tvout->default_tvStd;
2233209ff23fSmrg    if (tv_info->ucTV_SupportedStandard & NTSC_SUPPORT) {
2234209ff23fSmrg	ErrorF("NTSC ");
2235b7e1c893Smrg	tvout->SupportedTVStds |= TV_STD_NTSC;
2236209ff23fSmrg    }
2237209ff23fSmrg    if (tv_info->ucTV_SupportedStandard & NTSCJ_SUPPORT) {
2238209ff23fSmrg	ErrorF("NTSC-J ");
2239b7e1c893Smrg	tvout->SupportedTVStds |= TV_STD_NTSC_J;
2240209ff23fSmrg    }
2241209ff23fSmrg    if (tv_info->ucTV_SupportedStandard & PAL_SUPPORT) {
2242209ff23fSmrg	ErrorF("PAL ");
2243b7e1c893Smrg	tvout->SupportedTVStds |= TV_STD_PAL;
2244209ff23fSmrg    }
2245209ff23fSmrg    if (tv_info->ucTV_SupportedStandard & PALM_SUPPORT) {
2246209ff23fSmrg	ErrorF("PAL-M ");
2247b7e1c893Smrg	tvout->SupportedTVStds |= TV_STD_PAL_M;
2248209ff23fSmrg    }
2249209ff23fSmrg    if (tv_info->ucTV_SupportedStandard & PAL60_SUPPORT) {
2250209ff23fSmrg	ErrorF("PAL-60 ");
2251b7e1c893Smrg	tvout->SupportedTVStds |= TV_STD_PAL_60;
2252209ff23fSmrg    }
2253209ff23fSmrg    ErrorF("\n");
2254209ff23fSmrg
2255209ff23fSmrg    if (tv_info->ucExt_TV_ASIC_ID) {
2256209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unknown external TV ASIC\n");
2257209ff23fSmrg	return FALSE;
2258209ff23fSmrg    }
2259209ff23fSmrg
2260209ff23fSmrg    return TRUE;
2261209ff23fSmrg}
2262209ff23fSmrg
2263209ff23fSmrgBool
2264ad43ddacSmrgRADEONGetATOMClockInfo(ScrnInfoPtr pScrn)
2265ad43ddacSmrg{
2266ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
2267ad43ddacSmrg    RADEONPLLPtr pll = &info->pll;
2268ad43ddacSmrg    atomDataTablesPtr atomDataPtr;
2269ad43ddacSmrg    uint8_t crev, frev;
2270ad43ddacSmrg
2271ad43ddacSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
2272ad43ddacSmrg    if (!rhdAtomGetTableRevisionAndSize(
2273ad43ddacSmrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->FirmwareInfo.base),
2274ad43ddacSmrg	    &crev,&frev,NULL)) {
2275ad43ddacSmrg	return FALSE;
2276ad43ddacSmrg    }
2277ad43ddacSmrg
2278ad43ddacSmrg    switch(crev) {
2279ad43ddacSmrg    case 1:
2280ad43ddacSmrg	info->sclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulDefaultEngineClock) / 100.0;
2281ad43ddacSmrg	info->mclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulDefaultMemoryClock) / 100.0;
2282ad43ddacSmrg	pll->xclk = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMaxPixelClock);
2283ad43ddacSmrg	pll->pll_in_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMinPixelClockPLL_Input);
2284ad43ddacSmrg	pll->pll_in_max = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMaxPixelClockPLL_Input);
2285ad43ddacSmrg	pll->pll_out_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMinPixelClockPLL_Output);
2286ad43ddacSmrg	pll->pll_out_max = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulMaxPixelClockPLL_Output);
2287ad43ddacSmrg	pll->reference_freq = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usReferenceClock);
2288ad43ddacSmrg	break;
2289ad43ddacSmrg    case 2:
2290ad43ddacSmrg    case 3:
2291ad43ddacSmrg    case 4:
2292ad43ddacSmrg    default:
2293ad43ddacSmrg	info->sclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulDefaultEngineClock) / 100.0;
2294ad43ddacSmrg	info->mclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulDefaultMemoryClock) / 100.0;
2295ad43ddacSmrg	pll->xclk = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMaxPixelClock);
2296ad43ddacSmrg	pll->pll_in_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMinPixelClockPLL_Input);
2297ad43ddacSmrg	pll->pll_in_max = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMaxPixelClockPLL_Input);
2298ad43ddacSmrg	pll->pll_out_min = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulMinPixelClockPLL_Output);
2299ad43ddacSmrg	pll->pll_out_max = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulMaxPixelClockPLL_Output);
2300ad43ddacSmrg	pll->reference_freq = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usReferenceClock);
2301ad43ddacSmrg	break;
2302ad43ddacSmrg    }
2303ad43ddacSmrg    pll->reference_div = 0;
23042f39173dSmrg    if (pll->pll_out_min == 0) {
23052f39173dSmrg	if (IS_AVIVO_VARIANT)
23062f39173dSmrg	    pll->pll_out_min = 64800;
23072f39173dSmrg	else
23082f39173dSmrg	    pll->pll_out_min = 20000;
23092f39173dSmrg    }
2310ad43ddacSmrg
2311ad43ddacSmrg    /* limiting the range is a good thing in most cases
2312ad43ddacSmrg     * as it limits the number of matching pll combinations,
2313ad43ddacSmrg     * however, some duallink DVI monitors seem to prefer combinations that
2314ad43ddacSmrg     * would be limited by this.  This may need to be revisited
2315ad43ddacSmrg     * per chip family.
2316ad43ddacSmrg     */
2317ad43ddacSmrg    if (!xf86ReturnOptValBool(info->Options, OPTION_NEW_PLL, TRUE)) {
2318ad43ddacSmrg	if (pll->pll_out_min > 64800)
2319ad43ddacSmrg	    pll->pll_out_min = 64800;
2320ad43ddacSmrg    }
2321ad43ddacSmrg
23220974d292Smrg    if (IS_DCE4_VARIANT) {
23230974d292Smrg	info->default_dispclk =
23240974d292Smrg	    le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_2_1->ulDefaultDispEngineClkFreq);
23250974d292Smrg	if (info->default_dispclk == 0)
23260974d292Smrg	    info->default_dispclk = 60000;
23270974d292Smrg	info->dp_extclk = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_2_1->usUniphyDPModeExtClkFreq);
23280974d292Smrg    }
2329ad43ddacSmrg    return TRUE;
2330ad43ddacSmrg}
2331ad43ddacSmrg
2332ad43ddacSmrgBool
2333ad43ddacSmrgRADEONATOMGetTVTimings(ScrnInfoPtr pScrn, int index, DisplayModePtr mode)
2334209ff23fSmrg{
2335209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2336209ff23fSmrg    ATOM_ANALOG_TV_INFO *tv_info;
2337b7e1c893Smrg    ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2;
2338b7e1c893Smrg    ATOM_DTD_FORMAT *dtd_timings;
2339b7e1c893Smrg    atomDataTablesPtr atomDataPtr;
2340b7e1c893Smrg    uint8_t crev, frev;
2341ad43ddacSmrg    uint16_t misc;
2342209ff23fSmrg
2343b7e1c893Smrg    atomDataPtr = info->atomBIOS->atomDataPtr;
2344b7e1c893Smrg    if (!rhdAtomGetTableRevisionAndSize(
2345b7e1c893Smrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->AnalogTV_Info.base),
2346b7e1c893Smrg	    &crev,&frev,NULL)) {
2347209ff23fSmrg	return FALSE;
2348b7e1c893Smrg    }
2349209ff23fSmrg
2350b7e1c893Smrg    switch(crev) {
2351b7e1c893Smrg    case 1:
2352b7e1c893Smrg	tv_info = atomDataPtr->AnalogTV_Info.AnalogTV_Info;
2353ad43ddacSmrg
2354b7e1c893Smrg	if (index > MAX_SUPPORTED_TV_TIMING)
2355b7e1c893Smrg	    return FALSE;
2356ad43ddacSmrg
2357ad43ddacSmrg	mode->CrtcHTotal     = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
2358ad43ddacSmrg	mode->CrtcHDisplay   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
2359ad43ddacSmrg	mode->CrtcHSyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
2360ad43ddacSmrg	mode->CrtcHSyncEnd   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) +
2361ad43ddacSmrg	                       le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
2362ad43ddacSmrg
2363ad43ddacSmrg	mode->CrtcVTotal     = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
2364ad43ddacSmrg	mode->CrtcVDisplay   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
2365ad43ddacSmrg	mode->CrtcVSyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
2366ad43ddacSmrg	mode->CrtcVSyncEnd   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) +
2367ad43ddacSmrg	                       le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
2368ad43ddacSmrg
2369ad43ddacSmrg	mode->Flags = 0;
2370ad43ddacSmrg	misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess);
2371ad43ddacSmrg	if (misc & ATOM_VSYNC_POLARITY)
2372ad43ddacSmrg	    mode->Flags |= V_NVSYNC;
2373ad43ddacSmrg	if (misc & ATOM_HSYNC_POLARITY)
2374ad43ddacSmrg	    mode->Flags |= V_NHSYNC;
2375ad43ddacSmrg	if (misc & ATOM_COMPOSITESYNC)
2376ad43ddacSmrg	    mode->Flags |= V_CSYNC;
2377ad43ddacSmrg	if (misc & ATOM_INTERLACE)
2378ad43ddacSmrg	    mode->Flags |= V_INTERLACE;
2379ad43ddacSmrg	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2380ad43ddacSmrg	    mode->Flags |= V_DBLSCAN;
2381ad43ddacSmrg
2382ad43ddacSmrg	mode->Clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
2383b7e1c893Smrg
2384b7e1c893Smrg	if (index == 1) {
2385b7e1c893Smrg		/* PAL timings appear to have wrong values for totals */
2386ad43ddacSmrg		mode->CrtcHTotal -= 1;
2387ad43ddacSmrg		mode->CrtcVTotal -= 1;
2388b7e1c893Smrg	}
2389b7e1c893Smrg	break;
2390b7e1c893Smrg    case 2:
2391b7e1c893Smrg	tv_info_v1_2 = atomDataPtr->AnalogTV_Info.AnalogTV_Info_v1_2;
2392b7e1c893Smrg	if (index > MAX_SUPPORTED_TV_TIMING_V1_2)
2393b7e1c893Smrg	    return FALSE;
2394209ff23fSmrg
2395b7e1c893Smrg	dtd_timings = &tv_info_v1_2->aModeTimings[index];
2396ad43ddacSmrg	mode->CrtcHTotal     = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHBlanking_Time);
2397ad43ddacSmrg	mode->CrtcHDisplay   = le16_to_cpu(dtd_timings->usHActive);
2398ad43ddacSmrg	mode->CrtcHSyncStart = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHSyncOffset);
2399ad43ddacSmrg	mode->CrtcHSyncEnd   = mode->CrtcHSyncStart + le16_to_cpu(dtd_timings->usHSyncWidth);
2400ad43ddacSmrg
2401ad43ddacSmrg	mode->CrtcVTotal     = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVBlanking_Time);
2402ad43ddacSmrg	mode->CrtcVDisplay   = le16_to_cpu(dtd_timings->usVActive);
2403ad43ddacSmrg	mode->CrtcVSyncStart = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVSyncOffset);
2404ad43ddacSmrg	mode->CrtcVSyncEnd   = mode->CrtcVSyncStart + le16_to_cpu(dtd_timings->usVSyncWidth);
2405ad43ddacSmrg
2406ad43ddacSmrg	mode->Flags = 0;
2407ad43ddacSmrg	misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
2408ad43ddacSmrg	if (misc & ATOM_VSYNC_POLARITY)
2409ad43ddacSmrg	    mode->Flags |= V_NVSYNC;
2410ad43ddacSmrg	if (misc & ATOM_HSYNC_POLARITY)
2411ad43ddacSmrg	    mode->Flags |= V_NHSYNC;
2412ad43ddacSmrg	if (misc & ATOM_COMPOSITESYNC)
2413ad43ddacSmrg	    mode->Flags |= V_CSYNC;
2414ad43ddacSmrg	if (misc & ATOM_INTERLACE)
2415ad43ddacSmrg	    mode->Flags |= V_INTERLACE;
2416ad43ddacSmrg	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2417ad43ddacSmrg	    mode->Flags |= V_DBLSCAN;
2418ad43ddacSmrg
2419ad43ddacSmrg	mode->Clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
2420ad43ddacSmrg
2421b7e1c893Smrg	break;
2422b7e1c893Smrg    }
2423209ff23fSmrg
2424209ff23fSmrg    return TRUE;
2425209ff23fSmrg}
2426209ff23fSmrg
2427b7e1c893Smrguint32_t
2428b7e1c893Smrgradeon_get_encoder_id_from_supported_device(ScrnInfoPtr pScrn, uint32_t supported_device, int dac)
2429209ff23fSmrg{
2430209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
2431b7e1c893Smrg    uint32_t ret = 0;
2432b7e1c893Smrg
2433b7e1c893Smrg    switch (supported_device) {
2434b7e1c893Smrg    case ATOM_DEVICE_CRT1_SUPPORT:
2435b7e1c893Smrg    case ATOM_DEVICE_TV1_SUPPORT:
2436b7e1c893Smrg    case ATOM_DEVICE_TV2_SUPPORT:
2437b7e1c893Smrg    case ATOM_DEVICE_CRT2_SUPPORT:
2438b7e1c893Smrg    case ATOM_DEVICE_CV_SUPPORT:
2439b7e1c893Smrg	switch (dac) {
2440b7e1c893Smrg	    // primary dac
2441b7e1c893Smrg	case 1:
2442b7e1c893Smrg	    if ((info->ChipFamily == CHIP_FAMILY_RS300) ||
2443b7e1c893Smrg		(info->ChipFamily == CHIP_FAMILY_RS400) ||
2444b7e1c893Smrg		(info->ChipFamily == CHIP_FAMILY_RS480))
2445b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
2446b7e1c893Smrg	    else if (IS_AVIVO_VARIANT)
2447b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1;
2448b7e1c893Smrg	    else
2449b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_DAC1;
2450b7e1c893Smrg	    break;
2451b7e1c893Smrg	    // secondary dac
2452b7e1c893Smrg	case 2:
2453b7e1c893Smrg	    if (IS_AVIVO_VARIANT)
2454b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2;
2455b7e1c893Smrg	    else {
2456b7e1c893Smrg		/*if (info->ChipFamily == CHIP_FAMILY_R200)
2457b7e1c893Smrg		    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2458b7e1c893Smrg		    else*/
2459b7e1c893Smrg		    ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
2460b7e1c893Smrg	    }
2461b7e1c893Smrg	    break;
2462b7e1c893Smrg	    // external dac
2463b7e1c893Smrg	case 3:
2464b7e1c893Smrg	    if (IS_AVIVO_VARIANT)
2465b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
2466b7e1c893Smrg	    else
2467b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2468b7e1c893Smrg	    break;
2469209ff23fSmrg	}
2470b7e1c893Smrg	break;
2471b7e1c893Smrg    case ATOM_DEVICE_LCD1_SUPPORT:
2472b7e1c893Smrg	if (IS_AVIVO_VARIANT)
2473b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
2474b7e1c893Smrg	else
2475b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_LVDS;
2476b7e1c893Smrg	break;
2477b7e1c893Smrg    case ATOM_DEVICE_DFP1_SUPPORT:
2478b7e1c893Smrg	if ((info->ChipFamily == CHIP_FAMILY_RS300) ||
2479b7e1c893Smrg	    (info->ChipFamily == CHIP_FAMILY_RS400) ||
2480b7e1c893Smrg	    (info->ChipFamily == CHIP_FAMILY_RS480))
2481b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2482b7e1c893Smrg	else if (IS_AVIVO_VARIANT)
2483b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1;
2484b7e1c893Smrg	else
2485b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_TMDS1;
2486b7e1c893Smrg	break;
2487b7e1c893Smrg    case ATOM_DEVICE_LCD2_SUPPORT:
2488b7e1c893Smrg    case ATOM_DEVICE_DFP2_SUPPORT:
2489b7e1c893Smrg	if ((info->ChipFamily == CHIP_FAMILY_RS600) ||
2490b7e1c893Smrg	    (info->ChipFamily == CHIP_FAMILY_RS690) ||
2491b7e1c893Smrg	    (info->ChipFamily == CHIP_FAMILY_RS740))
2492b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_DDI;
2493b7e1c893Smrg	else if (IS_AVIVO_VARIANT)
2494b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
2495b7e1c893Smrg	else
2496b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2497b7e1c893Smrg	break;
2498b7e1c893Smrg    case ATOM_DEVICE_DFP3_SUPPORT:
2499b7e1c893Smrg	ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
2500b7e1c893Smrg	break;
2501209ff23fSmrg    }
2502209ff23fSmrg
2503b7e1c893Smrg    return ret;
2504209ff23fSmrg}
2505209ff23fSmrg
2506209ff23fSmrgBool
2507209ff23fSmrgRADEONGetATOMConnectorInfoFromBIOSConnectorTable (ScrnInfoPtr pScrn)
2508209ff23fSmrg{
2509209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
2510209ff23fSmrg    atomDataTablesPtr atomDataPtr;
2511209ff23fSmrg    uint8_t crev, frev;
2512209ff23fSmrg    int i, j;
2513b7e1c893Smrg    Bool enable_tv = FALSE;
2514b7e1c893Smrg
2515b7e1c893Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_ATOM_TVOUT, FALSE))
2516b7e1c893Smrg	enable_tv = TRUE;
2517209ff23fSmrg
2518209ff23fSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
2519209ff23fSmrg
2520209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(
2521209ff23fSmrg	    &(atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->sHeader),
2522209ff23fSmrg	    &crev,&frev,NULL)) {
2523209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Device Info Table found!\n");
2524209ff23fSmrg	return FALSE;
2525209ff23fSmrg    }
2526209ff23fSmrg
2527209ff23fSmrg    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2528209ff23fSmrg	ATOM_CONNECTOR_INFO_I2C ci
2529209ff23fSmrg	    = atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->asConnInfo[i];
2530209ff23fSmrg
2531209ff23fSmrg	if (!(le16_to_cpu(atomDataPtr->SupportedDevicesInfo
2532209ff23fSmrg			  .SupportedDevicesInfo->usDeviceSupport) & (1 << i))) {
2533209ff23fSmrg	    info->BiosConnector[i].valid = FALSE;
2534209ff23fSmrg	    continue;
2535209ff23fSmrg	}
2536209ff23fSmrg
2537b7e1c893Smrg	/* don't support CV yet */
2538209ff23fSmrg	if (i == ATOM_DEVICE_CV_INDEX) {
2539209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Skipping Component Video\n");
2540209ff23fSmrg	    info->BiosConnector[i].valid = FALSE;
2541209ff23fSmrg	    continue;
2542209ff23fSmrg	}
2543b7e1c893Smrg
2544b7e1c893Smrg	if (!enable_tv && (i == ATOM_DEVICE_TV1_INDEX)) {
2545209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Skipping TV-Out\n");
2546209ff23fSmrg	    info->BiosConnector[i].valid = FALSE;
2547209ff23fSmrg	    continue;
2548209ff23fSmrg	}
2549209ff23fSmrg
2550209ff23fSmrg	info->BiosConnector[i].valid = TRUE;
2551b7e1c893Smrg	info->BiosConnector[i].load_detection = TRUE;
2552b7e1c893Smrg	info->BiosConnector[i].shared_ddc = FALSE;
2553ad43ddacSmrg	info->BiosConnector[i].output_id = ci.sucI2cId.ucAccess;
2554209ff23fSmrg	info->BiosConnector[i].devices = (1 << i);
2555209ff23fSmrg	info->BiosConnector[i].ConnectorType = ci.sucConnectorInfo.sbfAccess.bfConnectorType;
2556209ff23fSmrg
2557209ff23fSmrg	if (info->BiosConnector[i].ConnectorType == CONNECTOR_NONE) {
2558209ff23fSmrg	    info->BiosConnector[i].valid = FALSE;
2559209ff23fSmrg	    continue;
2560209ff23fSmrg	}
2561209ff23fSmrg
2562209ff23fSmrg	/* don't assign a gpio for tv */
2563209ff23fSmrg	if ((i == ATOM_DEVICE_TV1_INDEX) ||
2564209ff23fSmrg	    (i == ATOM_DEVICE_TV2_INDEX) ||
2565209ff23fSmrg	    (i == ATOM_DEVICE_CV_INDEX))
2566209ff23fSmrg	    info->BiosConnector[i].ddc_i2c.valid = FALSE;
2567ad43ddacSmrg	else
2568209ff23fSmrg	    info->BiosConnector[i].ddc_i2c =
2569ad43ddacSmrg		RADEONLookupGPIOLineForDDC(pScrn, ci.sucI2cId.ucAccess);
2570209ff23fSmrg
2571b7e1c893Smrg	if (!radeon_add_encoder(pScrn,
2572b7e1c893Smrg			   radeon_get_encoder_id_from_supported_device(pScrn, (1 << i),
2573b7e1c893Smrg					  ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC),
2574b7e1c893Smrg				(1 << i)))
2575b7e1c893Smrg	    return FALSE;
2576209ff23fSmrg
2577209ff23fSmrg	/* Always set the connector type to VGA for CRT1/CRT2. if they are
2578209ff23fSmrg	 * shared with a DVI port, we'll pick up the DVI connector below when we
2579209ff23fSmrg	 * merge the outputs
2580209ff23fSmrg	 */
2581209ff23fSmrg	if ((i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) &&
2582209ff23fSmrg	    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I ||
2583209ff23fSmrg	     info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D ||
2584209ff23fSmrg	     info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A)) {
2585209ff23fSmrg	    info->BiosConnector[i].ConnectorType = CONNECTOR_VGA;
2586209ff23fSmrg	}
2587209ff23fSmrg
2588209ff23fSmrg	if (crev > 1) {
2589209ff23fSmrg	    ATOM_CONNECTOR_INC_SRC_BITMAP isb
2590209ff23fSmrg		= atomDataPtr->SupportedDevicesInfo
2591209ff23fSmrg		.SupportedDevicesInfo_HD->asIntSrcInfo[i];
2592209ff23fSmrg
2593209ff23fSmrg	    switch (isb.ucIntSrcBitmap) {
2594209ff23fSmrg		case 0x4:
2595209ff23fSmrg		    info->BiosConnector[i].hpd_mask = 0x00000001;
2596209ff23fSmrg		    break;
2597209ff23fSmrg		case 0xa:
2598209ff23fSmrg		    info->BiosConnector[i].hpd_mask = 0x00000100;
2599209ff23fSmrg		    break;
2600209ff23fSmrg		default:
2601209ff23fSmrg		    info->BiosConnector[i].hpd_mask = 0;
2602209ff23fSmrg		    break;
2603209ff23fSmrg	    }
2604b7e1c893Smrg	} else
2605209ff23fSmrg	    info->BiosConnector[i].hpd_mask = 0;
2606209ff23fSmrg
2607209ff23fSmrg	RADEONApplyATOMQuirks(pScrn, i);
2608209ff23fSmrg
2609209ff23fSmrg    }
2610209ff23fSmrg
2611209ff23fSmrg    /* CRTs/DFPs may share a port */
2612209ff23fSmrg    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2613209ff23fSmrg	if (info->BiosConnector[i].valid) {
2614209ff23fSmrg	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2615209ff23fSmrg		if (info->BiosConnector[j].valid && (i != j) ) {
2616209ff23fSmrg		    if (info->BiosConnector[i].output_id == info->BiosConnector[j].output_id) {
2617209ff23fSmrg			if (((i == ATOM_DEVICE_DFP1_INDEX) ||
2618209ff23fSmrg			     (i == ATOM_DEVICE_DFP2_INDEX) ||
2619209ff23fSmrg			     (i == ATOM_DEVICE_DFP3_INDEX)) &&
2620b7e1c893Smrg			    ((j == ATOM_DEVICE_CRT1_INDEX) ||
2621b7e1c893Smrg			     (j == ATOM_DEVICE_CRT2_INDEX))) {
2622209ff23fSmrg			    info->BiosConnector[i].devices |= info->BiosConnector[j].devices;
2623c503f109Smrg			    if (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D)
2624c503f109Smrg				info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_I;
2625209ff23fSmrg			    info->BiosConnector[j].valid = FALSE;
2626209ff23fSmrg			} else if (((j == ATOM_DEVICE_DFP1_INDEX) ||
2627b7e1c893Smrg				    (j == ATOM_DEVICE_DFP2_INDEX) ||
2628b7e1c893Smrg				    (j == ATOM_DEVICE_DFP3_INDEX)) &&
2629b7e1c893Smrg				   ((i == ATOM_DEVICE_CRT1_INDEX) ||
2630b7e1c893Smrg				    (i == ATOM_DEVICE_CRT2_INDEX))) {
2631209ff23fSmrg			    info->BiosConnector[j].devices |= info->BiosConnector[i].devices;
2632c503f109Smrg			    if (info->BiosConnector[j].ConnectorType == CONNECTOR_DVI_D)
2633c503f109Smrg				info->BiosConnector[j].ConnectorType = CONNECTOR_DVI_I;
2634209ff23fSmrg			    info->BiosConnector[i].valid = FALSE;
2635b7e1c893Smrg			} else {
2636b7e1c893Smrg			    info->BiosConnector[i].shared_ddc = TRUE;
2637b7e1c893Smrg			    info->BiosConnector[j].shared_ddc = TRUE;
2638209ff23fSmrg			}
2639209ff23fSmrg			/* other possible combos?  */
2640209ff23fSmrg		    }
2641209ff23fSmrg		}
2642209ff23fSmrg	    }
2643209ff23fSmrg	}
2644209ff23fSmrg    }
2645209ff23fSmrg
2646209ff23fSmrg    return TRUE;
2647209ff23fSmrg}
2648209ff23fSmrg
2649209ff23fSmrg# ifdef ATOM_BIOS_PARSER
2650209ff23fSmrgstatic AtomBiosResult
2651209ff23fSmrgrhdAtomExec (atomBiosHandlePtr handle,
2652209ff23fSmrg	     AtomBiosRequestID unused, AtomBiosArgPtr data)
2653209ff23fSmrg{
2654209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (xf86Screens[handle->scrnIndex]);
2655209ff23fSmrg    Bool ret = FALSE;
2656209ff23fSmrg    char *msg;
2657209ff23fSmrg    int idx = data->exec.index;
2658209ff23fSmrg    void *pspace = data->exec.pspace;
2659209ff23fSmrg    pointer *dataSpace = data->exec.dataSpace;
2660209ff23fSmrg
2661209ff23fSmrg    //RHDFUNCI(handle->scrnIndex);
2662209ff23fSmrg
2663209ff23fSmrg    if (dataSpace) {
2664209ff23fSmrg	if (!handle->fbBase && !handle->scratchBase)
2665209ff23fSmrg	    return ATOM_FAILED;
2666209ff23fSmrg	if (handle->fbBase) {
2667209ff23fSmrg	    if (!info->FB) {
2668209ff23fSmrg		xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: "
2669209ff23fSmrg			   "Cannot exec AtomBIOS: framebuffer not mapped\n",
2670209ff23fSmrg			   __func__);
2671209ff23fSmrg		return ATOM_FAILED;
2672209ff23fSmrg	    }
2673209ff23fSmrg	    *dataSpace = (uint8_t*)info->FB + handle->fbBase;
2674209ff23fSmrg	} else
2675209ff23fSmrg	    *dataSpace = (uint8_t*)handle->scratchBase;
2676209ff23fSmrg    }
2677209ff23fSmrg    ret = ParseTableWrapper(pspace, idx, handle,
2678209ff23fSmrg			    handle->BIOSBase,
2679209ff23fSmrg			    &msg);
2680209ff23fSmrg    if (!ret)
2681209ff23fSmrg	xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s\n",msg);
2682209ff23fSmrg    else
2683209ff23fSmrg	xf86DrvMsgVerb(handle->scrnIndex, X_INFO, 5, "%s\n",msg);
2684209ff23fSmrg
2685209ff23fSmrg    return (ret) ? ATOM_SUCCESS : ATOM_FAILED;
2686209ff23fSmrg}
2687209ff23fSmrg# endif
2688209ff23fSmrg
2689209ff23fSmrgAtomBiosResult
2690209ff23fSmrgRHDAtomBiosFunc(int scrnIndex, atomBiosHandlePtr handle,
2691209ff23fSmrg		AtomBiosRequestID id, AtomBiosArgPtr data)
2692209ff23fSmrg{
2693209ff23fSmrg    AtomBiosResult ret = ATOM_FAILED;
2694209ff23fSmrg    int i;
2695209ff23fSmrg    char *msg = NULL;
2696209ff23fSmrg    enum msgDataFormat msg_f = MSG_FORMAT_NONE;
2697209ff23fSmrg    AtomBiosRequestFunc req_func = NULL;
2698209ff23fSmrg
2699209ff23fSmrg    //RHDFUNCI(scrnIndex);
2700209ff23fSmrg
2701209ff23fSmrg    for (i = 0; AtomBiosRequestList[i].id != FUNC_END; i++) {
2702209ff23fSmrg	if (id ==  AtomBiosRequestList[i].id) {
2703209ff23fSmrg	    req_func = AtomBiosRequestList[i].request;
2704209ff23fSmrg	    msg = AtomBiosRequestList[i].message;
2705209ff23fSmrg	    msg_f = AtomBiosRequestList[i].message_format;
2706209ff23fSmrg	    break;
2707209ff23fSmrg	}
2708209ff23fSmrg    }
2709209ff23fSmrg
2710209ff23fSmrg    if (req_func == NULL) {
2711209ff23fSmrg	xf86DrvMsg(scrnIndex, X_ERROR, "Unknown AtomBIOS request: %i\n",id);
2712209ff23fSmrg	return ATOM_NOT_IMPLEMENTED;
2713209ff23fSmrg    }
2714209ff23fSmrg    /* Hack for now */
2715209ff23fSmrg    if (id == ATOMBIOS_INIT)
2716209ff23fSmrg	data->val = scrnIndex;
2717209ff23fSmrg
2718209ff23fSmrg    if (id == ATOMBIOS_INIT || handle)
2719209ff23fSmrg	ret = req_func(handle, id, data);
2720209ff23fSmrg
2721209ff23fSmrg    if (ret == ATOM_SUCCESS) {
2722209ff23fSmrg
2723209ff23fSmrg	switch (msg_f) {
2724209ff23fSmrg	    case MSG_FORMAT_DEC:
2725209ff23fSmrg		xf86DrvMsg(scrnIndex,X_INFO,"%s: %li\n", msg,
2726209ff23fSmrg			   (unsigned long) data->val);
2727209ff23fSmrg		break;
2728209ff23fSmrg	    case MSG_FORMAT_HEX:
2729209ff23fSmrg		xf86DrvMsg(scrnIndex,X_INFO,"%s: 0x%lx\n",msg ,
2730209ff23fSmrg			   (unsigned long) data->val);
2731209ff23fSmrg		break;
2732209ff23fSmrg	    case MSG_FORMAT_NONE:
2733209ff23fSmrg		xf86DrvMsgVerb(scrnIndex, 7, X_INFO,
2734209ff23fSmrg			       "Call to %s succeeded\n", msg);
2735209ff23fSmrg		break;
2736209ff23fSmrg	}
2737209ff23fSmrg
2738209ff23fSmrg    } else {
2739209ff23fSmrg
2740209ff23fSmrg	char *result = (ret == ATOM_FAILED) ? "failed"
2741209ff23fSmrg	    : "not implemented";
2742209ff23fSmrg	switch (msg_f) {
2743209ff23fSmrg	    case MSG_FORMAT_DEC:
2744209ff23fSmrg	    case MSG_FORMAT_HEX:
2745209ff23fSmrg		xf86DrvMsgVerb(scrnIndex, 1, X_WARNING,
2746209ff23fSmrg			       "Call to %s %s\n", msg, result);
2747209ff23fSmrg		break;
2748209ff23fSmrg	    case MSG_FORMAT_NONE:
2749209ff23fSmrg		xf86DrvMsg(scrnIndex,X_INFO,"Query for %s: %s\n", msg, result);
2750209ff23fSmrg		    break;
2751209ff23fSmrg	}
2752209ff23fSmrg    }
2753209ff23fSmrg    return ret;
2754209ff23fSmrg}
2755209ff23fSmrg
2756209ff23fSmrg# ifdef ATOM_BIOS_PARSER
2757209ff23fSmrgVOID*
2758209ff23fSmrgCailAllocateMemory(VOID *CAIL,UINT16 size)
2759209ff23fSmrg{
2760b7e1c893Smrg    void *ret;
2761209ff23fSmrg    CAILFUNC(CAIL);
2762209ff23fSmrg
2763b7e1c893Smrg    ret = malloc(size);
2764b7e1c893Smrg    memset(ret, 0, size);
2765b7e1c893Smrg    return ret;
2766209ff23fSmrg}
2767209ff23fSmrg
2768209ff23fSmrgVOID
2769209ff23fSmrgCailReleaseMemory(VOID *CAIL, VOID *addr)
2770209ff23fSmrg{
2771209ff23fSmrg    CAILFUNC(CAIL);
2772209ff23fSmrg
2773209ff23fSmrg    free(addr);
2774209ff23fSmrg}
2775209ff23fSmrg
2776209ff23fSmrgVOID
2777209ff23fSmrgCailDelayMicroSeconds(VOID *CAIL, UINT32 delay)
2778209ff23fSmrg{
2779209ff23fSmrg    CAILFUNC(CAIL);
2780209ff23fSmrg
2781209ff23fSmrg    usleep(delay);
2782209ff23fSmrg
2783209ff23fSmrg    /*DEBUGP(xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_INFO,"Delay %i usec\n",delay));*/
2784209ff23fSmrg}
2785209ff23fSmrg
2786209ff23fSmrgUINT32
2787209ff23fSmrgCailReadATIRegister(VOID* CAIL, UINT32 idx)
2788209ff23fSmrg{
2789209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2790ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
2791209ff23fSmrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2792209ff23fSmrg    unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
2793209ff23fSmrg    UINT32 ret;
2794ad43ddacSmrg    UINT32 mm_reg = idx << 2;
2795209ff23fSmrg    CAILFUNC(CAIL);
2796209ff23fSmrg
2797ad43ddacSmrg    if (mm_reg < info->MMIOSize)
2798ad43ddacSmrg	ret = INREG(mm_reg);
2799ad43ddacSmrg    else {
2800ad43ddacSmrg	OUTREG(RADEON_MM_INDEX, mm_reg);
2801ad43ddacSmrg	ret = INREG(RADEON_MM_DATA);
2802ad43ddacSmrg    }
2803ad43ddacSmrg
2804209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx << 2,ret));*/
2805209ff23fSmrg    return ret;
2806209ff23fSmrg}
2807209ff23fSmrg
2808209ff23fSmrgVOID
2809209ff23fSmrgCailWriteATIRegister(VOID *CAIL, UINT32 idx, UINT32 data)
2810209ff23fSmrg{
2811209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2812ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
2813209ff23fSmrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2814209ff23fSmrg    unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
2815ad43ddacSmrg    UINT32 mm_reg = idx << 2;
2816209ff23fSmrg    CAILFUNC(CAIL);
2817209ff23fSmrg
2818ad43ddacSmrg    if (mm_reg < info->MMIOSize)
2819ad43ddacSmrg	OUTREG(mm_reg, data);
2820ad43ddacSmrg    else {
2821ad43ddacSmrg	OUTREG(RADEON_MM_INDEX, mm_reg);
2822ad43ddacSmrg	OUTREG(RADEON_MM_DATA, data);
2823ad43ddacSmrg    }
2824ad43ddacSmrg
2825209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx << 2,data));*/
2826209ff23fSmrg}
2827209ff23fSmrg
2828209ff23fSmrgUINT32
2829209ff23fSmrgCailReadFBData(VOID* CAIL, UINT32 idx)
2830209ff23fSmrg{
2831209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2832209ff23fSmrg    RADEONInfoPtr  info   = RADEONPTR(pScrn);
2833209ff23fSmrg    UINT32 ret;
2834209ff23fSmrg
2835209ff23fSmrg    CAILFUNC(CAIL);
2836209ff23fSmrg
2837209ff23fSmrg    if (((atomBiosHandlePtr)CAIL)->fbBase) {
2838209ff23fSmrg	uint8_t *FBBase = (uint8_t*)info->FB;
2839209ff23fSmrg	ret =  *((uint32_t*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx));
2840209ff23fSmrg	/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,ret));*/
2841209ff23fSmrg    } else if (((atomBiosHandlePtr)CAIL)->scratchBase) {
2842209ff23fSmrg	ret = *(uint32_t*)((uint8_t*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx);
2843209ff23fSmrg	/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,ret));*/
2844209ff23fSmrg    } else {
2845209ff23fSmrg	xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
2846209ff23fSmrg		   "%s: no fbbase set\n",__func__);
2847209ff23fSmrg	return 0;
2848209ff23fSmrg    }
2849209ff23fSmrg    return ret;
2850209ff23fSmrg}
2851209ff23fSmrg
2852209ff23fSmrgVOID
2853209ff23fSmrgCailWriteFBData(VOID *CAIL, UINT32 idx, UINT32 data)
2854209ff23fSmrg{
2855209ff23fSmrg    CAILFUNC(CAIL);
2856209ff23fSmrg
2857209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx,data));*/
2858209ff23fSmrg    if (((atomBiosHandlePtr)CAIL)->fbBase) {
2859209ff23fSmrg	uint8_t *FBBase = (uint8_t*)
2860209ff23fSmrg	    RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->FB;
2861209ff23fSmrg	*((uint32_t*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx)) = data;
2862209ff23fSmrg    } else if (((atomBiosHandlePtr)CAIL)->scratchBase) {
2863209ff23fSmrg	*(uint32_t*)((uint8_t*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx) = data;
2864209ff23fSmrg    } else
2865209ff23fSmrg	xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
2866209ff23fSmrg		   "%s: no fbbase set\n",__func__);
2867209ff23fSmrg}
2868209ff23fSmrg
2869209ff23fSmrgULONG
2870209ff23fSmrgCailReadMC(VOID *CAIL, ULONG Address)
2871209ff23fSmrg{
2872209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2873209ff23fSmrg    ULONG ret;
2874209ff23fSmrg
2875209ff23fSmrg    CAILFUNC(CAIL);
2876209ff23fSmrg
2877209ff23fSmrg    ret = INMC(pScrn, Address);
2878209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,Address,ret));*/
2879209ff23fSmrg    return ret;
2880209ff23fSmrg}
2881209ff23fSmrg
2882209ff23fSmrgVOID
2883209ff23fSmrgCailWriteMC(VOID *CAIL, ULONG Address, ULONG data)
2884209ff23fSmrg{
2885209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2886209ff23fSmrg
2887209ff23fSmrg    CAILFUNC(CAIL);
2888209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,Address,data));*/
2889209ff23fSmrg    OUTMC(pScrn, Address, data);
2890209ff23fSmrg}
2891209ff23fSmrg
2892209ff23fSmrg#ifdef XSERVER_LIBPCIACCESS
2893209ff23fSmrg
2894209ff23fSmrgVOID
2895209ff23fSmrgCailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size)
2896209ff23fSmrg{
2897209ff23fSmrg    pci_device_cfg_read(RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->PciInfo,
2898209ff23fSmrg				ret,idx << 2 , size >> 3, NULL);
2899209ff23fSmrg}
2900209ff23fSmrg
2901209ff23fSmrgVOID
2902209ff23fSmrgCailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size)
2903209ff23fSmrg{
2904209ff23fSmrg    pci_device_cfg_write(RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->PciInfo,
2905209ff23fSmrg			 src, idx << 2, size >> 3, NULL);
2906209ff23fSmrg}
2907209ff23fSmrg
2908209ff23fSmrg#else
2909209ff23fSmrg
2910209ff23fSmrgVOID
2911209ff23fSmrgCailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size)
2912209ff23fSmrg{
2913209ff23fSmrg    PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag;
2914209ff23fSmrg
2915209ff23fSmrg    CAILFUNC(CAIL);
2916209ff23fSmrg
2917209ff23fSmrg    switch (size) {
2918209ff23fSmrg	case 8:
2919209ff23fSmrg	    *(uint8_t*)ret = pciReadByte(tag,idx << 2);
2920209ff23fSmrg	    break;
2921209ff23fSmrg	case 16:
2922209ff23fSmrg	    *(uint16_t*)ret = pciReadWord(tag,idx << 2);
2923209ff23fSmrg	    break;
2924209ff23fSmrg	case 32:
2925209ff23fSmrg	    *(uint32_t*)ret = pciReadLong(tag,idx << 2);
2926209ff23fSmrg	    break;
2927209ff23fSmrg	default:
2928209ff23fSmrg	xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,
2929209ff23fSmrg		   X_ERROR,"%s: Unsupported size: %i\n",
2930209ff23fSmrg		   __func__,(int)size);
2931209ff23fSmrg	return;
2932209ff23fSmrg	    break;
2933209ff23fSmrg    }
2934209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,*(unsigned int*)ret));*/
2935209ff23fSmrg
2936209ff23fSmrg}
2937209ff23fSmrg
2938209ff23fSmrgVOID
2939209ff23fSmrgCailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size)
2940209ff23fSmrg{
2941209ff23fSmrg    PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag;
2942209ff23fSmrg
2943209ff23fSmrg    CAILFUNC(CAIL);
2944209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx,(*(unsigned int*)src)));*/
2945209ff23fSmrg    switch (size) {
2946209ff23fSmrg	case 8:
2947209ff23fSmrg	    pciWriteByte(tag,idx << 2,*(uint8_t*)src);
2948209ff23fSmrg	    break;
2949209ff23fSmrg	case 16:
2950209ff23fSmrg	    pciWriteWord(tag,idx << 2,*(uint16_t*)src);
2951209ff23fSmrg	    break;
2952209ff23fSmrg	case 32:
2953209ff23fSmrg	    pciWriteLong(tag,idx << 2,*(uint32_t*)src);
2954209ff23fSmrg	    break;
2955209ff23fSmrg	default:
2956209ff23fSmrg	    xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
2957209ff23fSmrg		       "%s: Unsupported size: %i\n",__func__,(int)size);
2958209ff23fSmrg	    break;
2959209ff23fSmrg    }
2960209ff23fSmrg}
2961209ff23fSmrg#endif
2962209ff23fSmrg
2963209ff23fSmrgULONG
2964209ff23fSmrgCailReadPLL(VOID *CAIL, ULONG Address)
2965209ff23fSmrg{
2966209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2967209ff23fSmrg    ULONG ret;
2968209ff23fSmrg
2969209ff23fSmrg    CAILFUNC(CAIL);
2970209ff23fSmrg
2971209ff23fSmrg    ret = RADEONINPLL(pScrn, Address);
2972209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,Address,ret));*/
2973209ff23fSmrg    return ret;
2974209ff23fSmrg}
2975209ff23fSmrg
2976209ff23fSmrgVOID
2977209ff23fSmrgCailWritePLL(VOID *CAIL, ULONG Address,ULONG Data)
2978209ff23fSmrg{
2979209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2980209ff23fSmrg    CAILFUNC(CAIL);
2981209ff23fSmrg
2982209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,Address,Data));*/
2983209ff23fSmrg    RADEONOUTPLL(pScrn, Address, Data);
2984209ff23fSmrg}
2985209ff23fSmrg
2986209ff23fSmrgvoid
2987209ff23fSmrgatombios_get_command_table_version(atomBiosHandlePtr atomBIOS, int index, int *major, int *minor)
2988209ff23fSmrg{
2989209ff23fSmrg    ATOM_MASTER_COMMAND_TABLE *cmd_table = (void *)(atomBIOS->BIOSBase + atomBIOS->cmd_offset);
2990209ff23fSmrg    ATOM_MASTER_LIST_OF_COMMAND_TABLES *table_start;
2991209ff23fSmrg    ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *table_hdr;
2992209ff23fSmrg
2993209ff23fSmrg    //unsigned short *ptr;
2994209ff23fSmrg    unsigned short offset;
2995209ff23fSmrg
2996209ff23fSmrg    table_start = &cmd_table->ListOfCommandTables;
2997209ff23fSmrg
2998209ff23fSmrg    offset  = *(((unsigned short *)table_start) + index);
2999209ff23fSmrg
3000209ff23fSmrg    offset = le16_to_cpu(offset);
3001209ff23fSmrg    table_hdr = (ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *)(atomBIOS->BIOSBase + offset);
3002209ff23fSmrg
3003209ff23fSmrg    *major = table_hdr->CommonHeader.ucTableFormatRevision;
3004209ff23fSmrg    *minor = table_hdr->CommonHeader.ucTableContentRevision;
3005209ff23fSmrg}
3006209ff23fSmrg
3007209ff23fSmrg
3008b7e1c893SmrgUINT16 ATOM_BSWAP16(UINT16 x)
3009b7e1c893Smrg{
3010b7e1c893Smrg    return bswap_16(x);
3011b7e1c893Smrg}
3012b7e1c893Smrg
3013b7e1c893SmrgUINT32 ATOM_BSWAP32(UINT32 x)
3014b7e1c893Smrg{
3015b7e1c893Smrg    return bswap_32(x);
3016b7e1c893Smrg}
3017b7e1c893Smrg
3018b7e1c893Smrg
3019209ff23fSmrg#endif /* ATOM_BIOS */
3020