radeon_atombios.c revision 2f39173d
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);
785209ff23fSmrg    mode->CrtcHBlankStart = dtd->usHActive + dtd->ucHBorder;
786209ff23fSmrg    mode->CrtcHBlankEnd = mode->CrtcHBlankStart + le16_to_cpu(dtd->usHBlanking_Time);
787209ff23fSmrg    mode->CrtcHTotal = mode->HTotal = mode->CrtcHBlankEnd + dtd->ucHBorder;
788209ff23fSmrg    mode->CrtcVBlankStart = dtd->usVActive + dtd->ucVBorder;
789209ff23fSmrg    mode->CrtcVBlankEnd = mode->CrtcVBlankStart + le16_to_cpu(dtd->usVBlanking_Time);
790209ff23fSmrg    mode->CrtcVTotal = mode->VTotal = mode->CrtcVBlankEnd + dtd->ucVBorder;
791209ff23fSmrg    mode->CrtcHSyncStart = mode->HSyncStart = dtd->usHActive + le16_to_cpu(dtd->usHSyncOffset);
792209ff23fSmrg    mode->CrtcHSyncEnd = mode->HSyncEnd = mode->HSyncStart + le16_to_cpu(dtd->usHSyncWidth);
793209ff23fSmrg    mode->CrtcVSyncStart = mode->VSyncStart = 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
1536ad43ddacSmrg    num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1537ad43ddacSmrg	    sizeof(ATOM_GPIO_I2C_ASSIGMENT);
1538ad43ddacSmrg
1539ad43ddacSmrg    for (i = 0; i < num_indices; i++) {
1540ad43ddacSmrg	    gpio = &atomDataPtr->GPIO_I2C_Info->asGPIO_Info[i];
1541ad43ddacSmrg	    if (gpio->sucI2cId.ucAccess == id) {
1542ad43ddacSmrg		    i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
1543ad43ddacSmrg		    i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
1544ad43ddacSmrg		    i2c.put_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
1545ad43ddacSmrg		    i2c.put_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
1546ad43ddacSmrg		    i2c.get_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
1547ad43ddacSmrg		    i2c.get_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
1548ad43ddacSmrg		    i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
1549ad43ddacSmrg		    i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
1550ad43ddacSmrg		    i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
1551ad43ddacSmrg		    i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
1552ad43ddacSmrg		    i2c.put_clk_mask = (1 << gpio->ucClkEnShift);
1553ad43ddacSmrg		    i2c.put_data_mask = (1 << gpio->ucDataEnShift);
1554ad43ddacSmrg		    i2c.get_clk_mask = (1 << gpio->ucClkY_Shift);
1555ad43ddacSmrg		    i2c.get_data_mask = (1 <<  gpio->ucDataY_Shift);
1556ad43ddacSmrg		    i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
1557ad43ddacSmrg		    i2c.a_data_mask = (1 <<  gpio->ucDataA_Shift);
1558ad43ddacSmrg		    i2c.hw_line = gpio->sucI2cId.ucAccess;
1559ad43ddacSmrg		    i2c.hw_capable = gpio->sucI2cId.sbfAccess.bfHW_Capable;
1560ad43ddacSmrg		    i2c.valid = TRUE;
1561ad43ddacSmrg		    break;
1562ad43ddacSmrg	    }
1563ad43ddacSmrg    }
1564209ff23fSmrg
1565209ff23fSmrg#if 0
1566b7e1c893Smrg    ErrorF("id: %d\n", id);
1567ad43ddacSmrg    ErrorF("hw capable: %d\n", gpio->sucI2cId.sbfAccess.bfHW_Capable);
1568ad43ddacSmrg    ErrorF("hw engine id: %d\n", gpio->sucI2cId.sbfAccess.bfHW_EngineID);
1569ad43ddacSmrg    ErrorF("line mux %d\n", gpio->sucI2cId.sbfAccess.bfI2C_LineMux);
1570ad43ddacSmrg    ErrorF("mask_clk_reg: 0x%x\n", gpio->usClkMaskRegisterIndex * 4);
1571ad43ddacSmrg    ErrorF("mask_data_reg: 0x%x\n", gpio->usDataMaskRegisterIndex * 4);
1572ad43ddacSmrg    ErrorF("put_clk_reg: 0x%x\n", gpio->usClkEnRegisterIndex * 4);
1573ad43ddacSmrg    ErrorF("put_data_reg: 0x%x\n", gpio->usDataEnRegisterIndex * 4);
1574ad43ddacSmrg    ErrorF("get_clk_reg: 0x%x\n", gpio->usClkY_RegisterIndex * 4);
1575ad43ddacSmrg    ErrorF("get_data_reg: 0x%x\n", gpio->usDataY_RegisterIndex * 4);
1576ad43ddacSmrg    ErrorF("a_clk_reg: 0x%x\n", gpio->usClkA_RegisterIndex * 4);
1577ad43ddacSmrg    ErrorF("a_data_reg: 0x%x\n", gpio->usDataA_RegisterIndex * 4);
1578ad43ddacSmrg    ErrorF("mask_clk_mask: %d\n", gpio->ucClkMaskShift);
1579ad43ddacSmrg    ErrorF("mask_data_mask: %d\n", gpio->ucDataMaskShift);
1580ad43ddacSmrg    ErrorF("put_clk_mask: %d\n", gpio->ucClkEnShift);
1581ad43ddacSmrg    ErrorF("put_data_mask: %d\n", gpio->ucDataEnShift);
1582ad43ddacSmrg    ErrorF("get_clk_mask: %d\n", gpio->ucClkY_Shift);
1583ad43ddacSmrg    ErrorF("get_data_mask: %d\n", gpio->ucDataY_Shift);
1584ad43ddacSmrg    ErrorF("a_clk_mask: %d\n", gpio->ucClkA_Shift);
1585ad43ddacSmrg    ErrorF("a_data_mask: %d\n", gpio->ucDataA_Shift);
1586209ff23fSmrg#endif
1587209ff23fSmrg
1588209ff23fSmrg    return i2c;
1589209ff23fSmrg}
1590209ff23fSmrg
1591b7e1c893Smrgstatic RADEONI2CBusRec
1592b7e1c893SmrgrhdAtomParseI2CRecord(ScrnInfoPtr pScrn, atomBiosHandlePtr handle,
1593b7e1c893Smrg		      ATOM_I2C_RECORD *Record, int i)
1594b7e1c893Smrg{
1595b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1596ad43ddacSmrg    uint8_t *temp = &Record->sucI2cId;
1597b7e1c893Smrg
1598ad43ddacSmrg    info->BiosConnector[i].i2c_line_mux = *temp;
1599ad43ddacSmrg    info->BiosConnector[i].ucI2cId = *temp;
1600ad43ddacSmrg    return RADEONLookupGPIOLineForDDC(pScrn, *temp);
1601ad43ddacSmrg}
1602ad43ddacSmrg
1603ad43ddacSmrgstatic uint8_t
1604ad43ddacSmrgradeon_lookup_hpd_id(ScrnInfoPtr pScrn, ATOM_HPD_INT_RECORD *record)
1605ad43ddacSmrg{
1606ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1607ad43ddacSmrg    unsigned short size;
1608ad43ddacSmrg    uint8_t hpd = 0;
1609ad43ddacSmrg    int i, num_indices;
1610ad43ddacSmrg    struct _ATOM_GPIO_PIN_LUT *gpio_info;
1611ad43ddacSmrg    ATOM_GPIO_PIN_ASSIGNMENT *pin;
1612ad43ddacSmrg    atomDataTablesPtr atomDataPtr;
1613ad43ddacSmrg    uint8_t crev, frev;
1614ad43ddacSmrg    uint32_t reg;
1615ad43ddacSmrg
1616ad43ddacSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
1617ad43ddacSmrg
1618ad43ddacSmrg    if (!rhdAtomGetTableRevisionAndSize(
1619ad43ddacSmrg	    &(atomDataPtr->GPIO_Pin_LUT->sHeader),
1620ad43ddacSmrg	    &crev,&frev,&size)) {
1621ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No GPIO Pin Table found!\n");
1622ad43ddacSmrg	return hpd;
1623ad43ddacSmrg    }
1624ad43ddacSmrg
1625ad43ddacSmrg    num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
1626ad43ddacSmrg
1627ad43ddacSmrg    if (IS_DCE4_VARIANT)
1628ad43ddacSmrg	reg = EVERGREEN_DC_GPIO_HPD_A;
1629ad43ddacSmrg    else
1630ad43ddacSmrg	reg = AVIVO_DC_GPIO_HPD_A;
1631ad43ddacSmrg
1632ad43ddacSmrg    gpio_info = atomDataPtr->GPIO_Pin_LUT;
1633ad43ddacSmrg    for (i = 0; i < num_indices; i++) {
1634ad43ddacSmrg	pin = &gpio_info->asGPIO_Pin[i];
1635ad43ddacSmrg	if (record->ucHPDIntGPIOID == pin->ucGPIO_ID) {
1636ad43ddacSmrg	    if ((pin->usGpioPin_AIndex * 4) == reg) {
1637ad43ddacSmrg		switch (pin->ucGpioPinBitShift) {
1638ad43ddacSmrg		case 0:
1639ad43ddacSmrg		default:
1640ad43ddacSmrg		    hpd = 0;
1641ad43ddacSmrg		    break;
1642ad43ddacSmrg		case 8:
1643ad43ddacSmrg		    hpd = 1;
1644ad43ddacSmrg		    break;
1645ad43ddacSmrg		case 16:
1646ad43ddacSmrg		    hpd = 2;
1647ad43ddacSmrg		    break;
1648ad43ddacSmrg		case 24:
1649ad43ddacSmrg		    hpd = 3;
1650ad43ddacSmrg		    break;
1651ad43ddacSmrg		case 26:
1652ad43ddacSmrg		    hpd = 4;
1653ad43ddacSmrg		    break;
1654ad43ddacSmrg		case 28:
1655ad43ddacSmrg		    hpd = 5;
1656ad43ddacSmrg		    break;
1657ad43ddacSmrg		}
1658ad43ddacSmrg		break;
1659ad43ddacSmrg	    }
1660ad43ddacSmrg	}
1661ad43ddacSmrg    }
1662ad43ddacSmrg
1663ad43ddacSmrg    return hpd;
1664b7e1c893Smrg}
1665b7e1c893Smrg
1666b7e1c893Smrgstatic void RADEONApplyATOMQuirks(ScrnInfoPtr pScrn, int index)
1667b7e1c893Smrg{
1668b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1669b7e1c893Smrg
1670b7e1c893Smrg    /* Asus M2A-VM HDMI board lists the DVI port as HDMI */
1671b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RS690_791E) &&
1672b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1673b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x826d)) {
1674b7e1c893Smrg	if ((info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) &&
1675b7e1c893Smrg	    (info->BiosConnector[index].devices & ATOM_DEVICE_DFP3_SUPPORT)) {
1676b7e1c893Smrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D;
1677b7e1c893Smrg	}
1678b7e1c893Smrg    }
1679c503f109Smrg
1680ad43ddacSmrg    /* RS600 board lists the DVI port as HDMI */
1681ad43ddacSmrg    if ((info->Chipset == PCI_CHIP_RS600_7941) &&
1682ad43ddacSmrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1849) &&
1683ad43ddacSmrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x7941)) {
1684ad43ddacSmrg	if ((info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) &&
1685ad43ddacSmrg	    (info->BiosConnector[index].devices & ATOM_DEVICE_DFP3_SUPPORT)) {
1686ad43ddacSmrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D;
1687ad43ddacSmrg	}
1688ad43ddacSmrg    }
1689ad43ddacSmrg
1690b7e1c893Smrg    /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
1691b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RS600_7941) &&
1692b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x147b) &&
1693b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x2412)) {
1694b7e1c893Smrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_DVI_I)
1695b7e1c893Smrg	    info->BiosConnector[index].valid = FALSE;
1696b7e1c893Smrg    }
1697b7e1c893Smrg
1698b7e1c893Smrg    /* Falcon NW laptop lists vga ddc line for LVDS */
1699b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RV410_5653) &&
1700b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1462) &&
1701b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0291)) {
1702b7e1c893Smrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_LVDS) {
1703b7e1c893Smrg	    info->BiosConnector[index].ddc_i2c.valid = FALSE;
1704b7e1c893Smrg	}
1705b7e1c893Smrg    }
1706b7e1c893Smrg
1707b7e1c893Smrg    /* Funky macbooks */
1708b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RV530_71C5) &&
1709b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) &&
1710b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) {
1711b7e1c893Smrg	if ((index == ATOM_DEVICE_CRT1_INDEX) ||
1712b7e1c893Smrg	    (index == ATOM_DEVICE_CRT2_INDEX) ||
1713b7e1c893Smrg	    (index == ATOM_DEVICE_DFP2_INDEX))
1714b7e1c893Smrg	    info->BiosConnector[index].valid = FALSE;
1715b7e1c893Smrg
1716b7e1c893Smrg	if (index == ATOM_DEVICE_DFP1_INDEX) {
1717b7e1c893Smrg	    info->BiosConnector[index].devices |= ATOM_DEVICE_CRT2_SUPPORT;
1718b7e1c893Smrg	}
1719b7e1c893Smrg    }
1720b7e1c893Smrg
1721b7e1c893Smrg    /* ASUS HD 3600 XT board lists the DVI port as HDMI */
1722b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RV635_9598) &&
1723b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1724b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01da)) {
1725ad43ddacSmrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A)
1726ad43ddacSmrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_I;
1727b7e1c893Smrg    }
1728b7e1c893Smrg
1729c503f109Smrg    /* ASUS HD 3450 board lists the DVI port as HDMI */
1730c503f109Smrg    if ((info->Chipset == PCI_CHIP_RV620_95C5) &&
1731c503f109Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
1732c503f109Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01e2)) {
1733ad43ddacSmrg	if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A)
1734ad43ddacSmrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_I;
1735c503f109Smrg    }
1736c503f109Smrg
1737c503f109Smrg    /* some BIOSes seem to report DAC on HDMI - usually this is a board with
1738c503f109Smrg     * HDMI + VGA reporting as HDMI
1739c503f109Smrg     */
1740ad43ddacSmrg    if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) {
1741c503f109Smrg	if (info->BiosConnector[index].devices & (ATOM_DEVICE_CRT_SUPPORT)) {
1742c503f109Smrg	    info->BiosConnector[index].devices &= ~(ATOM_DEVICE_DFP_SUPPORT);
1743c503f109Smrg	    info->BiosConnector[index].ConnectorType = CONNECTOR_VGA;
1744c503f109Smrg	    info->BiosConnector[index].connector_object = 0;
1745ad43ddacSmrg	}
1746c503f109Smrg    }
1747b7e1c893Smrg
1748b7e1c893Smrg}
1749b7e1c893Smrg
1750b7e1c893Smrguint32_t
1751b7e1c893Smrgradeon_get_device_index(uint32_t device_support)
1752b7e1c893Smrg{
1753b7e1c893Smrg    uint32_t device_index = 0;
1754b7e1c893Smrg
1755b7e1c893Smrg    if (device_support == 0)
1756b7e1c893Smrg	return 0;
1757b7e1c893Smrg
1758b7e1c893Smrg    while ((device_support & 1) == 0) {
1759b7e1c893Smrg	device_support >>= 1;
1760b7e1c893Smrg	device_index++;
1761b7e1c893Smrg    }
1762b7e1c893Smrg    return device_index;
1763b7e1c893Smrg}
1764b7e1c893Smrg
1765b7e1c893Smrgradeon_encoder_ptr
1766b7e1c893Smrgradeon_get_encoder(xf86OutputPtr output)
1767b7e1c893Smrg{
1768b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1769b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR(output->scrn);
1770b7e1c893Smrg
1771b7e1c893Smrg    if (radeon_output->active_device)
1772b7e1c893Smrg	return info->encoders[radeon_get_device_index(radeon_output->active_device)];
1773b7e1c893Smrg    else
1774b7e1c893Smrg	return NULL;
1775b7e1c893Smrg}
1776b7e1c893Smrg
1777b7e1c893SmrgBool
1778b7e1c893Smrgradeon_add_encoder(ScrnInfoPtr pScrn, uint32_t encoder_id, uint32_t device_support)
1779b7e1c893Smrg{
1780b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1781b7e1c893Smrg    uint32_t device_index = radeon_get_device_index(device_support);
1782b7e1c893Smrg    int i;
1783b7e1c893Smrg
1784b7e1c893Smrg    if (device_support == 0) {
1785b7e1c893Smrg	ErrorF("device support == 0\n");
1786b7e1c893Smrg	return FALSE;
1787b7e1c893Smrg    }
1788b7e1c893Smrg
1789b7e1c893Smrg    if (info->encoders[device_index] != NULL)
1790b7e1c893Smrg	return TRUE;
1791b7e1c893Smrg    else {
1792b7e1c893Smrg	/* look for the encoder */
1793b7e1c893Smrg	for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
1794b7e1c893Smrg	    if ((info->encoders[i] != NULL) && (info->encoders[i]->encoder_id == encoder_id)) {
1795b7e1c893Smrg		info->encoders[device_index] = info->encoders[i];
1796b7e1c893Smrg		switch (encoder_id) {
1797b7e1c893Smrg		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1798b7e1c893Smrg		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1799b7e1c893Smrg		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1800b7e1c893Smrg		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1801b7e1c893Smrg		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1802b7e1c893Smrg		    if (device_support & ATOM_DEVICE_LCD1_SUPPORT) {
1803b7e1c893Smrg			if (info->encoders[device_index]->dev_priv == NULL) {
1804b7e1c893Smrg			    info->encoders[device_index]->dev_priv =
18052f39173dSmrg				(radeon_lvds_ptr)calloc(1,sizeof(radeon_lvds_rec));
1806b7e1c893Smrg			    if (info->encoders[device_index]->dev_priv == NULL) {
18072f39173dSmrg				ErrorF("calloc failed\n");
1808b7e1c893Smrg				return FALSE;
1809b7e1c893Smrg			    } else
1810b7e1c893Smrg				RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1811b7e1c893Smrg			}
1812b7e1c893Smrg		    }
1813b7e1c893Smrg		    break;
1814b7e1c893Smrg		}
1815b7e1c893Smrg		return TRUE;
1816b7e1c893Smrg	    }
1817b7e1c893Smrg	}
1818b7e1c893Smrg
18192f39173dSmrg	info->encoders[device_index] = (radeon_encoder_ptr)calloc(1,sizeof(radeon_encoder_rec));
1820b7e1c893Smrg	if (info->encoders[device_index] != NULL) {
1821b7e1c893Smrg	    info->encoders[device_index]->encoder_id = encoder_id;
1822b7e1c893Smrg	    info->encoders[device_index]->devices = 0;
1823b7e1c893Smrg	    info->encoders[device_index]->dev_priv = NULL;
1824b7e1c893Smrg	    // add dev_priv stuff
1825b7e1c893Smrg	    switch (encoder_id) {
1826b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
18272f39173dSmrg		    info->encoders[device_index]->dev_priv = (radeon_lvds_ptr)calloc(1,sizeof(radeon_lvds_rec));
1828b7e1c893Smrg		    if (info->encoders[device_index]->dev_priv == NULL) {
18292f39173dSmrg			ErrorF("calloc failed\n");
1830b7e1c893Smrg			return FALSE;
1831b7e1c893Smrg		    } else {
1832b7e1c893Smrg			if (info->IsAtomBios)
1833b7e1c893Smrg			    RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1834b7e1c893Smrg			else
1835b7e1c893Smrg			    RADEONGetLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1836b7e1c893Smrg		    }
1837b7e1c893Smrg		break;
1838b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1839b7e1c893Smrg		if (!IS_AVIVO_VARIANT) {
18402f39173dSmrg		    info->encoders[device_index]->dev_priv = (radeon_tvdac_ptr)calloc(1,sizeof(radeon_tvdac_rec));
1841b7e1c893Smrg		    if (info->encoders[device_index]->dev_priv == NULL) {
18422f39173dSmrg			ErrorF("calloc failed\n");
1843b7e1c893Smrg			return FALSE;
1844b7e1c893Smrg		    } else
1845b7e1c893Smrg			RADEONGetTVDacAdjInfo(pScrn, (radeon_tvdac_ptr)info->encoders[device_index]->dev_priv);
1846b7e1c893Smrg		}
1847b7e1c893Smrg		break;
1848b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1849b7e1c893Smrg		if (!IS_AVIVO_VARIANT) {
18502f39173dSmrg		    info->encoders[device_index]->dev_priv = (radeon_tmds_ptr)calloc(1,sizeof(radeon_tmds_rec));
1851b7e1c893Smrg		    if (info->encoders[device_index]->dev_priv == NULL) {
18522f39173dSmrg			ErrorF("calloc failed\n");
1853b7e1c893Smrg			return FALSE;
1854b7e1c893Smrg		    } else
1855b7e1c893Smrg			RADEONGetTMDSInfo(pScrn, (radeon_tmds_ptr)info->encoders[device_index]->dev_priv);
1856b7e1c893Smrg		}
1857b7e1c893Smrg		break;
1858b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1859b7e1c893Smrg		if (!IS_AVIVO_VARIANT) {
18602f39173dSmrg		    info->encoders[device_index]->dev_priv = (radeon_dvo_ptr)calloc(1,sizeof(radeon_dvo_rec));
1861b7e1c893Smrg		    if (info->encoders[device_index]->dev_priv == NULL) {
18622f39173dSmrg			ErrorF("calloc failed\n");
1863b7e1c893Smrg			return FALSE;
1864b7e1c893Smrg		    } else
1865b7e1c893Smrg			RADEONGetExtTMDSInfo(pScrn, (radeon_dvo_ptr)info->encoders[device_index]->dev_priv);
1866b7e1c893Smrg		}
1867b7e1c893Smrg		break;
1868b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1869b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1870b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1871b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1872b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1873b7e1c893Smrg		if (device_support & ATOM_DEVICE_LCD1_SUPPORT) {
18742f39173dSmrg		    info->encoders[device_index]->dev_priv = (radeon_lvds_ptr)calloc(1,sizeof(radeon_lvds_rec));
1875b7e1c893Smrg		    if (info->encoders[device_index]->dev_priv == NULL) {
18762f39173dSmrg			ErrorF("calloc failed\n");
1877b7e1c893Smrg			return FALSE;
1878b7e1c893Smrg		    } else
1879b7e1c893Smrg			RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
1880b7e1c893Smrg		}
1881b7e1c893Smrg		break;
1882b7e1c893Smrg	    }
1883b7e1c893Smrg	    return TRUE;
1884b7e1c893Smrg	} else {
18852f39173dSmrg	    ErrorF("calloc failed\n");
1886b7e1c893Smrg	    return FALSE;
1887b7e1c893Smrg	}
1888b7e1c893Smrg    }
1889b7e1c893Smrg
1890b7e1c893Smrg}
1891b7e1c893Smrg
1892209ff23fSmrgBool
1893209ff23fSmrgRADEONGetATOMConnectorInfoFromBIOSObject (ScrnInfoPtr pScrn)
1894209ff23fSmrg{
1895209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
1896209ff23fSmrg    uint8_t crev, frev;
1897209ff23fSmrg    unsigned short size;
1898209ff23fSmrg    atomDataTablesPtr atomDataPtr;
1899209ff23fSmrg    ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
1900b7e1c893Smrg    ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
1901209ff23fSmrg    ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj = NULL;
1902b7e1c893Smrg    int i, j, path_size, device_support;
1903b7e1c893Smrg    Bool enable_tv = FALSE;
1904b7e1c893Smrg
1905b7e1c893Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_ATOM_TVOUT, FALSE))
1906b7e1c893Smrg	enable_tv = TRUE;
1907209ff23fSmrg
1908209ff23fSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
1909209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->Object_Header), &crev, &frev, &size))
1910209ff23fSmrg	return FALSE;
1911209ff23fSmrg
1912209ff23fSmrg    if (crev < 2)
1913209ff23fSmrg	return FALSE;
1914209ff23fSmrg
1915b7e1c893Smrg    path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
1916b7e1c893Smrg	((char *)&atomDataPtr->Object_Header->sHeader +
1917b7e1c893Smrg	 le16_to_cpu(atomDataPtr->Object_Header->usDisplayPathTableOffset));
1918209ff23fSmrg    con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
1919209ff23fSmrg	((char *)&atomDataPtr->Object_Header->sHeader +
1920209ff23fSmrg	 le16_to_cpu(atomDataPtr->Object_Header->usConnectorObjectTableOffset));
1921b7e1c893Smrg    device_support = le16_to_cpu(atomDataPtr->Object_Header->usDeviceSupport);
1922b7e1c893Smrg
1923b7e1c893Smrg    path_size = 0;
1924b7e1c893Smrg    for (i = 0; i < path_obj->ucNumOfDispPath; i++) {
1925b7e1c893Smrg	uint8_t *addr = (uint8_t *)path_obj->asDispPath;
1926b7e1c893Smrg	ATOM_DISPLAY_OBJECT_PATH *path;
1927b7e1c893Smrg	addr += path_size;
1928b7e1c893Smrg	path = (ATOM_DISPLAY_OBJECT_PATH *)addr;
1929c503f109Smrg	path_size += le16_to_cpu(path->usSize);
1930b7e1c893Smrg
1931c503f109Smrg	if (device_support & le16_to_cpu(path->usDeviceTag)) {
1932b7e1c893Smrg	    uint8_t con_obj_id, con_obj_num, con_obj_type;
1933b7e1c893Smrg
1934c503f109Smrg	    con_obj_id = (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
1935c503f109Smrg	    con_obj_num = (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
1936c503f109Smrg	    con_obj_type = (le16_to_cpu(path->usConnObjectId) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
1937b7e1c893Smrg
1938c503f109Smrg	    if ((le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_TV1_SUPPORT) ||
1939c503f109Smrg		(le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_TV2_SUPPORT)) {
1940b7e1c893Smrg		if (!enable_tv) {
1941b7e1c893Smrg		    info->BiosConnector[i].valid = FALSE;
1942b7e1c893Smrg		    continue;
1943b7e1c893Smrg		}
1944b7e1c893Smrg	    }
1945209ff23fSmrg
1946b7e1c893Smrg	    /* don't support CV yet */
1947c503f109Smrg	    if (le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_CV_SUPPORT) {
1948b7e1c893Smrg		info->BiosConnector[i].valid = FALSE;
1949b7e1c893Smrg		continue;
1950b7e1c893Smrg	    }
1951209ff23fSmrg
1952b7e1c893Smrg	    if (info->IsIGP &&
1953b7e1c893Smrg		(con_obj_id == CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) {
1954b7e1c893Smrg		uint32_t slot_config, ct;
1955209ff23fSmrg
1956b7e1c893Smrg		igp_obj = info->atomBIOS->atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2;
1957209ff23fSmrg
1958b7e1c893Smrg		if (!igp_obj)
1959b7e1c893Smrg		    info->BiosConnector[i].ConnectorType = object_connector_convert[con_obj_id];
1960b7e1c893Smrg		else {
1961b7e1c893Smrg		    if (con_obj_num == 1)
1962b7e1c893Smrg			slot_config = igp_obj->ulDDISlot1Config;
1963b7e1c893Smrg		    else
1964b7e1c893Smrg			slot_config = igp_obj->ulDDISlot2Config;
1965209ff23fSmrg
1966b7e1c893Smrg		    ct = (slot_config  >> 16) & 0xff;
1967b7e1c893Smrg		    info->BiosConnector[i].ConnectorType = object_connector_convert[ct];
1968ad43ddacSmrg		    info->BiosConnector[i].connector_object_id = ct;
1969b7e1c893Smrg		    info->BiosConnector[i].igp_lane_info = slot_config & 0xffff;
1970b7e1c893Smrg		}
1971ad43ddacSmrg	    } else {
1972b7e1c893Smrg		info->BiosConnector[i].ConnectorType = object_connector_convert[con_obj_id];
1973ad43ddacSmrg		info->BiosConnector[i].connector_object_id = con_obj_id;
1974ad43ddacSmrg	    }
1975b7e1c893Smrg
1976b7e1c893Smrg	    if (info->BiosConnector[i].ConnectorType == CONNECTOR_NONE) {
1977b7e1c893Smrg		info->BiosConnector[i].valid = FALSE;
1978b7e1c893Smrg		continue;
1979b7e1c893Smrg	    } else
1980b7e1c893Smrg		info->BiosConnector[i].valid = TRUE;
1981c503f109Smrg	    info->BiosConnector[i].devices = le16_to_cpu(path->usDeviceTag);
1982c503f109Smrg	    info->BiosConnector[i].connector_object = le16_to_cpu(path->usConnObjectId);
1983b7e1c893Smrg
1984c503f109Smrg	    for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
1985b7e1c893Smrg		uint8_t enc_obj_id, enc_obj_num, enc_obj_type;
1986b7e1c893Smrg
1987c503f109Smrg		enc_obj_id = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
1988c503f109Smrg		enc_obj_num = (le16_to_cpu(path->usGraphicObjIds[j]) & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
1989c503f109Smrg		enc_obj_type = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
1990b7e1c893Smrg
1991b7e1c893Smrg		if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
1992b7e1c893Smrg		    if (enc_obj_num == 2)
1993b7e1c893Smrg			info->BiosConnector[i].linkb = TRUE;
1994b7e1c893Smrg		    else
1995b7e1c893Smrg			info->BiosConnector[i].linkb = FALSE;
1996b7e1c893Smrg
1997c503f109Smrg		    if (!radeon_add_encoder(pScrn, enc_obj_id, le16_to_cpu(path->usDeviceTag)))
1998b7e1c893Smrg			return FALSE;
1999b7e1c893Smrg		}
2000209ff23fSmrg	    }
2001209ff23fSmrg
2002b7e1c893Smrg	    /* look up gpio for ddc */
2003c503f109Smrg	    if ((le16_to_cpu(path->usDeviceTag) & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
2004b7e1c893Smrg		for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
2005c503f109Smrg		    if (le16_to_cpu(path->usConnObjectId) == le16_to_cpu(con_obj->asObjects[j].usObjectID)) {
2006b7e1c893Smrg			ATOM_COMMON_RECORD_HEADER *Record = (ATOM_COMMON_RECORD_HEADER *)
2007b7e1c893Smrg			    ((char *)&atomDataPtr->Object_Header->sHeader
2008b7e1c893Smrg			     + le16_to_cpu(con_obj->asObjects[j].usRecordOffset));
2009b7e1c893Smrg
2010b7e1c893Smrg			while (Record->ucRecordType > 0
2011b7e1c893Smrg			       && Record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER ) {
2012b7e1c893Smrg
2013b7e1c893Smrg			    /*ErrorF("record type %d\n", Record->ucRecordType);*/
2014b7e1c893Smrg			    switch (Record->ucRecordType) {
2015b7e1c893Smrg			    case ATOM_I2C_RECORD_TYPE:
2016b7e1c893Smrg				info->BiosConnector[i].ddc_i2c =
2017b7e1c893Smrg				    rhdAtomParseI2CRecord(pScrn, info->atomBIOS,
2018b7e1c893Smrg							  (ATOM_I2C_RECORD *)Record, j);
2019b7e1c893Smrg				break;
2020b7e1c893Smrg			    case ATOM_HPD_INT_RECORD_TYPE:
2021ad43ddacSmrg				info->BiosConnector[i].hpd_id =
2022ad43ddacSmrg				    radeon_lookup_hpd_id(pScrn,
2023ad43ddacSmrg							 (ATOM_HPD_INT_RECORD *)Record);
2024b7e1c893Smrg				break;
2025b7e1c893Smrg			    case ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE:
2026b7e1c893Smrg				break;
2027b7e1c893Smrg			    }
2028b7e1c893Smrg
2029b7e1c893Smrg			    Record = (ATOM_COMMON_RECORD_HEADER*)
2030b7e1c893Smrg				((char *)Record + Record->ucRecordSize);
2031b7e1c893Smrg			}
2032b7e1c893Smrg			break;
2033b7e1c893Smrg		    }
2034b7e1c893Smrg		}
2035b7e1c893Smrg	    }
2036b7e1c893Smrg	}
2037b7e1c893Smrg	RADEONApplyATOMQuirks(pScrn, i);
2038b7e1c893Smrg    }
2039209ff23fSmrg
2040b7e1c893Smrg    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2041b7e1c893Smrg	if (info->BiosConnector[i].valid) {
2042b7e1c893Smrg	    /* shared connectors */
2043b7e1c893Smrg	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2044b7e1c893Smrg		if (info->BiosConnector[j].valid && (i != j) ) {
2045b7e1c893Smrg		    if (info->BiosConnector[i].connector_object == info->BiosConnector[j].connector_object) {
2046b7e1c893Smrg			info->BiosConnector[i].devices |= info->BiosConnector[j].devices;
2047b7e1c893Smrg			info->BiosConnector[j].valid = FALSE;
2048b7e1c893Smrg		    }
2049b7e1c893Smrg		}
2050b7e1c893Smrg	    }
2051b7e1c893Smrg	    /* shared ddc */
2052b7e1c893Smrg	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2053b7e1c893Smrg		if (info->BiosConnector[j].valid && (i != j) ) {
2054b7e1c893Smrg		    if (info->BiosConnector[i].i2c_line_mux == info->BiosConnector[j].i2c_line_mux) {
2055b7e1c893Smrg			info->BiosConnector[i].shared_ddc = TRUE;
2056b7e1c893Smrg			info->BiosConnector[j].shared_ddc = TRUE;
2057b7e1c893Smrg		    }
2058b7e1c893Smrg		}
2059209ff23fSmrg	    }
2060209ff23fSmrg	}
2061b7e1c893Smrg    }
2062209ff23fSmrg
2063b7e1c893Smrg    return TRUE;
2064b7e1c893Smrg}
2065209ff23fSmrg
2066b7e1c893Smrgstatic void
2067b7e1c893SmrgRADEONGetATOMLVDSInfo(ScrnInfoPtr pScrn, radeon_lvds_ptr lvds)
2068b7e1c893Smrg{
2069b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2070b7e1c893Smrg    radeon_native_mode_ptr native_mode = &lvds->native_mode;
2071b7e1c893Smrg    atomDataTablesPtr atomDataPtr;
2072b7e1c893Smrg    uint8_t crev, frev;
2073ad43ddacSmrg    uint16_t misc;
2074209ff23fSmrg
2075b7e1c893Smrg    atomDataPtr = info->atomBIOS->atomDataPtr;
2076209ff23fSmrg
2077b7e1c893Smrg    if (!rhdAtomGetTableRevisionAndSize(
2078b7e1c893Smrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
2079b7e1c893Smrg	    &frev,&crev,NULL)) {
2080b7e1c893Smrg	return;
2081b7e1c893Smrg    }
2082209ff23fSmrg
2083b7e1c893Smrg    switch (crev) {
2084b7e1c893Smrg    case 1:
2085b7e1c893Smrg	native_mode->PanelXRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHActive);
2086b7e1c893Smrg	native_mode->PanelYRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVActive);
2087b7e1c893Smrg	native_mode->DotClock   = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usPixClk) * 10;
2088b7e1c893Smrg	native_mode->HBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHBlanking_Time);
2089b7e1c893Smrg	native_mode->HOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHSyncOffset);
2090b7e1c893Smrg	native_mode->HSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHSyncWidth);
2091b7e1c893Smrg	native_mode->VBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVBlanking_Time);
2092b7e1c893Smrg	native_mode->VOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVSyncOffset);
2093b7e1c893Smrg	native_mode->VSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVSyncWidth);
2094ad43ddacSmrg	misc = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.susModeMiscInfo.usAccess);
2095ad43ddacSmrg	if (misc & ATOM_VSYNC_POLARITY)
2096ad43ddacSmrg	    native_mode->Flags |= V_NVSYNC;
2097ad43ddacSmrg	if (misc & ATOM_HSYNC_POLARITY)
2098ad43ddacSmrg	    native_mode->Flags |= V_NHSYNC;
2099ad43ddacSmrg	if (misc & ATOM_COMPOSITESYNC)
2100ad43ddacSmrg	    native_mode->Flags |= V_CSYNC;
2101ad43ddacSmrg	if (misc & ATOM_INTERLACE)
2102ad43ddacSmrg	    native_mode->Flags |= V_INTERLACE;
2103ad43ddacSmrg	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2104ad43ddacSmrg	    native_mode->Flags |= V_DBLSCAN;
2105b7e1c893Smrg	lvds->PanelPwrDly = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->usOffDelayInMs);
2106b7e1c893Smrg	lvds->lvds_misc   =  atomDataPtr->LVDS_Info.LVDS_Info->ucLVDS_Misc;
2107b7e1c893Smrg	lvds->lvds_ss_id  =  atomDataPtr->LVDS_Info.LVDS_Info->ucSS_Id;
2108b7e1c893Smrg	break;
2109b7e1c893Smrg    case 2:
2110b7e1c893Smrg	native_mode->PanelXRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHActive);
2111b7e1c893Smrg	native_mode->PanelYRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVActive);
2112b7e1c893Smrg	native_mode->DotClock   = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usPixClk) * 10;
2113b7e1c893Smrg	native_mode->HBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHBlanking_Time);
2114b7e1c893Smrg	native_mode->HOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHSyncOffset);
2115b7e1c893Smrg	native_mode->HSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHSyncWidth);
2116b7e1c893Smrg	native_mode->VBlank     = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVBlanking_Time);
2117b7e1c893Smrg	native_mode->VOverPlus  = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVSyncOffset);
2118b7e1c893Smrg	native_mode->VSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVSyncWidth);
2119ad43ddacSmrg	misc = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.susModeMiscInfo.usAccess);
2120ad43ddacSmrg	if (misc & ATOM_VSYNC_POLARITY)
2121ad43ddacSmrg	    native_mode->Flags |= V_NVSYNC;
2122ad43ddacSmrg	if (misc & ATOM_HSYNC_POLARITY)
2123ad43ddacSmrg	    native_mode->Flags |= V_NHSYNC;
2124ad43ddacSmrg	if (misc & ATOM_COMPOSITESYNC)
2125ad43ddacSmrg	    native_mode->Flags |= V_CSYNC;
2126ad43ddacSmrg	if (misc & ATOM_INTERLACE)
2127ad43ddacSmrg	    native_mode->Flags |= V_INTERLACE;
2128ad43ddacSmrg	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2129ad43ddacSmrg	    native_mode->Flags |= V_DBLSCAN;
2130b7e1c893Smrg	lvds->PanelPwrDly = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->usOffDelayInMs);
2131b7e1c893Smrg	lvds->lvds_misc   =  atomDataPtr->LVDS_Info.LVDS_Info_v12->ucLVDS_Misc;
2132b7e1c893Smrg	lvds->lvds_ss_id  =  atomDataPtr->LVDS_Info.LVDS_Info_v12->ucSS_Id;
2133b7e1c893Smrg	break;
2134209ff23fSmrg    }
2135b7e1c893Smrg    native_mode->Flags = 0;
2136b7e1c893Smrg
2137b7e1c893Smrg    if (lvds->PanelPwrDly > 2000 || lvds->PanelPwrDly < 0)
2138b7e1c893Smrg	lvds->PanelPwrDly = 2000;
2139b7e1c893Smrg
2140b7e1c893Smrg    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2141b7e1c893Smrg	       "LVDS Info:\n"
2142b7e1c893Smrg	       "XRes: %d, YRes: %d, DotClock: %d\n"
2143b7e1c893Smrg	       "HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n"
2144b7e1c893Smrg	       "VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n",
2145b7e1c893Smrg	       native_mode->PanelXRes, native_mode->PanelYRes, native_mode->DotClock,
2146b7e1c893Smrg	       native_mode->HBlank, native_mode->HOverPlus, native_mode->HSyncWidth,
2147b7e1c893Smrg	       native_mode->VBlank, native_mode->VOverPlus, native_mode->VSyncWidth);
2148209ff23fSmrg}
2149209ff23fSmrg
2150ad43ddacSmrgvoid
2151ad43ddacSmrgRADEONATOMGetIGPInfo(ScrnInfoPtr pScrn)
2152ad43ddacSmrg{
2153ad43ddacSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2154ad43ddacSmrg    atomDataTablesPtr atomDataPtr;
2155ad43ddacSmrg    unsigned short size;
2156ad43ddacSmrg    uint8_t crev, frev;
2157ad43ddacSmrg
2158ad43ddacSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
2159ad43ddacSmrg
2160ad43ddacSmrg    if (!rhdAtomGetTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->IntegratedSystemInfo.base), &frev, &crev, &size))
2161ad43ddacSmrg	return;
2162ad43ddacSmrg
2163ad43ddacSmrg    switch (crev) {
2164ad43ddacSmrg    case 1:
2165ad43ddacSmrg	info->igp_sideport_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->ulBootUpMemoryClock / 100.0;
2166ad43ddacSmrg	info->igp_system_mclk = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usK8MemoryClock);
2167ad43ddacSmrg	info->igp_ht_link_clk = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usFSBClock);
2168ad43ddacSmrg	info->igp_ht_link_width = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->ucHTLinkWidth;
2169ad43ddacSmrg	break;
2170ad43ddacSmrg    case 2:
2171ad43ddacSmrg	info->igp_sideport_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulBootUpSidePortClock / 100.0;
2172ad43ddacSmrg	info->igp_system_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulBootUpUMAClock / 100.0;
2173ad43ddacSmrg	info->igp_ht_link_clk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulHTLinkFreq / 100.0;
2174ad43ddacSmrg	info->igp_ht_link_width = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->usMinHTLinkWidth);
2175ad43ddacSmrg	break;
2176ad43ddacSmrg    }
2177ad43ddacSmrg}
2178ad43ddacSmrg
2179209ff23fSmrgBool
2180209ff23fSmrgRADEONGetATOMTVInfo(xf86OutputPtr output)
2181209ff23fSmrg{
2182209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
2183209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2184209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2185b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
2186209ff23fSmrg    ATOM_ANALOG_TV_INFO *tv_info;
2187209ff23fSmrg
2188b7e1c893Smrg    tv_info = info->atomBIOS->atomDataPtr->AnalogTV_Info.AnalogTV_Info;
2189209ff23fSmrg
2190209ff23fSmrg    if (!tv_info)
2191209ff23fSmrg	return FALSE;
2192209ff23fSmrg
2193209ff23fSmrg    switch(tv_info->ucTV_BootUpDefaultStandard) {
2194209ff23fSmrg    case NTSCJ_SUPPORT:
2195b7e1c893Smrg	tvout->default_tvStd = TV_STD_NTSC_J;
2196209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC-J\n");
2197209ff23fSmrg	break;
2198209ff23fSmrg    case PAL_SUPPORT:
2199b7e1c893Smrg	tvout->default_tvStd = TV_STD_PAL;
2200209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL\n");
2201209ff23fSmrg	break;
2202209ff23fSmrg    case PALM_SUPPORT:
2203b7e1c893Smrg	tvout->default_tvStd = TV_STD_PAL_M;
2204209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-M\n");
2205209ff23fSmrg	break;
2206209ff23fSmrg    case PAL60_SUPPORT:
2207b7e1c893Smrg	tvout->default_tvStd = TV_STD_PAL_60;
2208209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-60\n");
2209209ff23fSmrg	break;
2210b7e1c893Smrg    default:
2211b7e1c893Smrg    case NTSC_SUPPORT:
2212b7e1c893Smrg	tvout->default_tvStd = TV_STD_NTSC;
2213b7e1c893Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC\n");
2214b7e1c893Smrg	break;
2215209ff23fSmrg    }
2216209ff23fSmrg
2217b7e1c893Smrg    tvout->tvStd = tvout->default_tvStd;
2218209ff23fSmrg
2219209ff23fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standards supported by chip: ");
2220b7e1c893Smrg    tvout->SupportedTVStds = tvout->default_tvStd;
2221209ff23fSmrg    if (tv_info->ucTV_SupportedStandard & NTSC_SUPPORT) {
2222209ff23fSmrg	ErrorF("NTSC ");
2223b7e1c893Smrg	tvout->SupportedTVStds |= TV_STD_NTSC;
2224209ff23fSmrg    }
2225209ff23fSmrg    if (tv_info->ucTV_SupportedStandard & NTSCJ_SUPPORT) {
2226209ff23fSmrg	ErrorF("NTSC-J ");
2227b7e1c893Smrg	tvout->SupportedTVStds |= TV_STD_NTSC_J;
2228209ff23fSmrg    }
2229209ff23fSmrg    if (tv_info->ucTV_SupportedStandard & PAL_SUPPORT) {
2230209ff23fSmrg	ErrorF("PAL ");
2231b7e1c893Smrg	tvout->SupportedTVStds |= TV_STD_PAL;
2232209ff23fSmrg    }
2233209ff23fSmrg    if (tv_info->ucTV_SupportedStandard & PALM_SUPPORT) {
2234209ff23fSmrg	ErrorF("PAL-M ");
2235b7e1c893Smrg	tvout->SupportedTVStds |= TV_STD_PAL_M;
2236209ff23fSmrg    }
2237209ff23fSmrg    if (tv_info->ucTV_SupportedStandard & PAL60_SUPPORT) {
2238209ff23fSmrg	ErrorF("PAL-60 ");
2239b7e1c893Smrg	tvout->SupportedTVStds |= TV_STD_PAL_60;
2240209ff23fSmrg    }
2241209ff23fSmrg    ErrorF("\n");
2242209ff23fSmrg
2243209ff23fSmrg    if (tv_info->ucExt_TV_ASIC_ID) {
2244209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unknown external TV ASIC\n");
2245209ff23fSmrg	return FALSE;
2246209ff23fSmrg    }
2247209ff23fSmrg
2248209ff23fSmrg    return TRUE;
2249209ff23fSmrg}
2250209ff23fSmrg
2251209ff23fSmrgBool
2252ad43ddacSmrgRADEONGetATOMClockInfo(ScrnInfoPtr pScrn)
2253ad43ddacSmrg{
2254ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
2255ad43ddacSmrg    RADEONPLLPtr pll = &info->pll;
2256ad43ddacSmrg    atomDataTablesPtr atomDataPtr;
2257ad43ddacSmrg    uint8_t crev, frev;
2258ad43ddacSmrg
2259ad43ddacSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
2260ad43ddacSmrg    if (!rhdAtomGetTableRevisionAndSize(
2261ad43ddacSmrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->FirmwareInfo.base),
2262ad43ddacSmrg	    &crev,&frev,NULL)) {
2263ad43ddacSmrg	return FALSE;
2264ad43ddacSmrg    }
2265ad43ddacSmrg
2266ad43ddacSmrg    switch(crev) {
2267ad43ddacSmrg    case 1:
2268ad43ddacSmrg	info->sclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulDefaultEngineClock) / 100.0;
2269ad43ddacSmrg	info->mclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulDefaultMemoryClock) / 100.0;
2270ad43ddacSmrg	pll->xclk = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMaxPixelClock);
2271ad43ddacSmrg	pll->pll_in_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMinPixelClockPLL_Input);
2272ad43ddacSmrg	pll->pll_in_max = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMaxPixelClockPLL_Input);
2273ad43ddacSmrg	pll->pll_out_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usMinPixelClockPLL_Output);
2274ad43ddacSmrg	pll->pll_out_max = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->ulMaxPixelClockPLL_Output);
2275ad43ddacSmrg	pll->reference_freq = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo->usReferenceClock);
2276ad43ddacSmrg	break;
2277ad43ddacSmrg    case 2:
2278ad43ddacSmrg    case 3:
2279ad43ddacSmrg    case 4:
2280ad43ddacSmrg    default:
2281ad43ddacSmrg	info->sclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulDefaultEngineClock) / 100.0;
2282ad43ddacSmrg	info->mclk = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulDefaultMemoryClock) / 100.0;
2283ad43ddacSmrg	pll->xclk = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMaxPixelClock);
2284ad43ddacSmrg	pll->pll_in_min = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMinPixelClockPLL_Input);
2285ad43ddacSmrg	pll->pll_in_max = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usMaxPixelClockPLL_Input);
2286ad43ddacSmrg	pll->pll_out_min = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulMinPixelClockPLL_Output);
2287ad43ddacSmrg	pll->pll_out_max = le32_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->ulMaxPixelClockPLL_Output);
2288ad43ddacSmrg	pll->reference_freq = le16_to_cpu(atomDataPtr->FirmwareInfo.FirmwareInfo_V_1_2->usReferenceClock);
2289ad43ddacSmrg	break;
2290ad43ddacSmrg    }
2291ad43ddacSmrg    pll->reference_div = 0;
22922f39173dSmrg    if (pll->pll_out_min == 0) {
22932f39173dSmrg	if (IS_AVIVO_VARIANT)
22942f39173dSmrg	    pll->pll_out_min = 64800;
22952f39173dSmrg	else
22962f39173dSmrg	    pll->pll_out_min = 20000;
22972f39173dSmrg    }
2298ad43ddacSmrg
2299ad43ddacSmrg    /* limiting the range is a good thing in most cases
2300ad43ddacSmrg     * as it limits the number of matching pll combinations,
2301ad43ddacSmrg     * however, some duallink DVI monitors seem to prefer combinations that
2302ad43ddacSmrg     * would be limited by this.  This may need to be revisited
2303ad43ddacSmrg     * per chip family.
2304ad43ddacSmrg     */
2305ad43ddacSmrg    if (!xf86ReturnOptValBool(info->Options, OPTION_NEW_PLL, TRUE)) {
2306ad43ddacSmrg	if (pll->pll_out_min > 64800)
2307ad43ddacSmrg	    pll->pll_out_min = 64800;
2308ad43ddacSmrg    }
2309ad43ddacSmrg
2310ad43ddacSmrg    return TRUE;
2311ad43ddacSmrg}
2312ad43ddacSmrg
2313ad43ddacSmrgBool
2314ad43ddacSmrgRADEONATOMGetTVTimings(ScrnInfoPtr pScrn, int index, DisplayModePtr mode)
2315209ff23fSmrg{
2316209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
2317209ff23fSmrg    ATOM_ANALOG_TV_INFO *tv_info;
2318b7e1c893Smrg    ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2;
2319b7e1c893Smrg    ATOM_DTD_FORMAT *dtd_timings;
2320b7e1c893Smrg    atomDataTablesPtr atomDataPtr;
2321b7e1c893Smrg    uint8_t crev, frev;
2322ad43ddacSmrg    uint16_t misc;
2323209ff23fSmrg
2324b7e1c893Smrg    atomDataPtr = info->atomBIOS->atomDataPtr;
2325b7e1c893Smrg    if (!rhdAtomGetTableRevisionAndSize(
2326b7e1c893Smrg	    (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->AnalogTV_Info.base),
2327b7e1c893Smrg	    &crev,&frev,NULL)) {
2328209ff23fSmrg	return FALSE;
2329b7e1c893Smrg    }
2330209ff23fSmrg
2331b7e1c893Smrg    switch(crev) {
2332b7e1c893Smrg    case 1:
2333b7e1c893Smrg	tv_info = atomDataPtr->AnalogTV_Info.AnalogTV_Info;
2334ad43ddacSmrg
2335b7e1c893Smrg	if (index > MAX_SUPPORTED_TV_TIMING)
2336b7e1c893Smrg	    return FALSE;
2337ad43ddacSmrg
2338ad43ddacSmrg	mode->CrtcHTotal     = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
2339ad43ddacSmrg	mode->CrtcHDisplay   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
2340ad43ddacSmrg	mode->CrtcHSyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
2341ad43ddacSmrg	mode->CrtcHSyncEnd   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) +
2342ad43ddacSmrg	                       le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
2343ad43ddacSmrg
2344ad43ddacSmrg	mode->CrtcVTotal     = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
2345ad43ddacSmrg	mode->CrtcVDisplay   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
2346ad43ddacSmrg	mode->CrtcVSyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
2347ad43ddacSmrg	mode->CrtcVSyncEnd   = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) +
2348ad43ddacSmrg	                       le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
2349ad43ddacSmrg
2350ad43ddacSmrg	mode->Flags = 0;
2351ad43ddacSmrg	misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess);
2352ad43ddacSmrg	if (misc & ATOM_VSYNC_POLARITY)
2353ad43ddacSmrg	    mode->Flags |= V_NVSYNC;
2354ad43ddacSmrg	if (misc & ATOM_HSYNC_POLARITY)
2355ad43ddacSmrg	    mode->Flags |= V_NHSYNC;
2356ad43ddacSmrg	if (misc & ATOM_COMPOSITESYNC)
2357ad43ddacSmrg	    mode->Flags |= V_CSYNC;
2358ad43ddacSmrg	if (misc & ATOM_INTERLACE)
2359ad43ddacSmrg	    mode->Flags |= V_INTERLACE;
2360ad43ddacSmrg	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2361ad43ddacSmrg	    mode->Flags |= V_DBLSCAN;
2362ad43ddacSmrg
2363ad43ddacSmrg	mode->Clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
2364b7e1c893Smrg
2365b7e1c893Smrg	if (index == 1) {
2366b7e1c893Smrg		/* PAL timings appear to have wrong values for totals */
2367ad43ddacSmrg		mode->CrtcHTotal -= 1;
2368ad43ddacSmrg		mode->CrtcVTotal -= 1;
2369b7e1c893Smrg	}
2370b7e1c893Smrg	break;
2371b7e1c893Smrg    case 2:
2372b7e1c893Smrg	tv_info_v1_2 = atomDataPtr->AnalogTV_Info.AnalogTV_Info_v1_2;
2373b7e1c893Smrg	if (index > MAX_SUPPORTED_TV_TIMING_V1_2)
2374b7e1c893Smrg	    return FALSE;
2375209ff23fSmrg
2376b7e1c893Smrg	dtd_timings = &tv_info_v1_2->aModeTimings[index];
2377ad43ddacSmrg	mode->CrtcHTotal     = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHBlanking_Time);
2378ad43ddacSmrg	mode->CrtcHDisplay   = le16_to_cpu(dtd_timings->usHActive);
2379ad43ddacSmrg	mode->CrtcHSyncStart = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHSyncOffset);
2380ad43ddacSmrg	mode->CrtcHSyncEnd   = mode->CrtcHSyncStart + le16_to_cpu(dtd_timings->usHSyncWidth);
2381ad43ddacSmrg
2382ad43ddacSmrg	mode->CrtcVTotal     = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVBlanking_Time);
2383ad43ddacSmrg	mode->CrtcVDisplay   = le16_to_cpu(dtd_timings->usVActive);
2384ad43ddacSmrg	mode->CrtcVSyncStart = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVSyncOffset);
2385ad43ddacSmrg	mode->CrtcVSyncEnd   = mode->CrtcVSyncStart + le16_to_cpu(dtd_timings->usVSyncWidth);
2386ad43ddacSmrg
2387ad43ddacSmrg	mode->Flags = 0;
2388ad43ddacSmrg	misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
2389ad43ddacSmrg	if (misc & ATOM_VSYNC_POLARITY)
2390ad43ddacSmrg	    mode->Flags |= V_NVSYNC;
2391ad43ddacSmrg	if (misc & ATOM_HSYNC_POLARITY)
2392ad43ddacSmrg	    mode->Flags |= V_NHSYNC;
2393ad43ddacSmrg	if (misc & ATOM_COMPOSITESYNC)
2394ad43ddacSmrg	    mode->Flags |= V_CSYNC;
2395ad43ddacSmrg	if (misc & ATOM_INTERLACE)
2396ad43ddacSmrg	    mode->Flags |= V_INTERLACE;
2397ad43ddacSmrg	if (misc & ATOM_DOUBLE_CLOCK_MODE)
2398ad43ddacSmrg	    mode->Flags |= V_DBLSCAN;
2399ad43ddacSmrg
2400ad43ddacSmrg	mode->Clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
2401ad43ddacSmrg
2402b7e1c893Smrg	break;
2403b7e1c893Smrg    }
2404209ff23fSmrg
2405209ff23fSmrg    return TRUE;
2406209ff23fSmrg}
2407209ff23fSmrg
2408b7e1c893Smrguint32_t
2409b7e1c893Smrgradeon_get_encoder_id_from_supported_device(ScrnInfoPtr pScrn, uint32_t supported_device, int dac)
2410209ff23fSmrg{
2411209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
2412b7e1c893Smrg    uint32_t ret = 0;
2413b7e1c893Smrg
2414b7e1c893Smrg    switch (supported_device) {
2415b7e1c893Smrg    case ATOM_DEVICE_CRT1_SUPPORT:
2416b7e1c893Smrg    case ATOM_DEVICE_TV1_SUPPORT:
2417b7e1c893Smrg    case ATOM_DEVICE_TV2_SUPPORT:
2418b7e1c893Smrg    case ATOM_DEVICE_CRT2_SUPPORT:
2419b7e1c893Smrg    case ATOM_DEVICE_CV_SUPPORT:
2420b7e1c893Smrg	switch (dac) {
2421b7e1c893Smrg	    // primary dac
2422b7e1c893Smrg	case 1:
2423b7e1c893Smrg	    if ((info->ChipFamily == CHIP_FAMILY_RS300) ||
2424b7e1c893Smrg		(info->ChipFamily == CHIP_FAMILY_RS400) ||
2425b7e1c893Smrg		(info->ChipFamily == CHIP_FAMILY_RS480))
2426b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
2427b7e1c893Smrg	    else if (IS_AVIVO_VARIANT)
2428b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1;
2429b7e1c893Smrg	    else
2430b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_DAC1;
2431b7e1c893Smrg	    break;
2432b7e1c893Smrg	    // secondary dac
2433b7e1c893Smrg	case 2:
2434b7e1c893Smrg	    if (IS_AVIVO_VARIANT)
2435b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2;
2436b7e1c893Smrg	    else {
2437b7e1c893Smrg		/*if (info->ChipFamily == CHIP_FAMILY_R200)
2438b7e1c893Smrg		    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2439b7e1c893Smrg		    else*/
2440b7e1c893Smrg		    ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
2441b7e1c893Smrg	    }
2442b7e1c893Smrg	    break;
2443b7e1c893Smrg	    // external dac
2444b7e1c893Smrg	case 3:
2445b7e1c893Smrg	    if (IS_AVIVO_VARIANT)
2446b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
2447b7e1c893Smrg	    else
2448b7e1c893Smrg		ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2449b7e1c893Smrg	    break;
2450209ff23fSmrg	}
2451b7e1c893Smrg	break;
2452b7e1c893Smrg    case ATOM_DEVICE_LCD1_SUPPORT:
2453b7e1c893Smrg	if (IS_AVIVO_VARIANT)
2454b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
2455b7e1c893Smrg	else
2456b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_LVDS;
2457b7e1c893Smrg	break;
2458b7e1c893Smrg    case ATOM_DEVICE_DFP1_SUPPORT:
2459b7e1c893Smrg	if ((info->ChipFamily == CHIP_FAMILY_RS300) ||
2460b7e1c893Smrg	    (info->ChipFamily == CHIP_FAMILY_RS400) ||
2461b7e1c893Smrg	    (info->ChipFamily == CHIP_FAMILY_RS480))
2462b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2463b7e1c893Smrg	else if (IS_AVIVO_VARIANT)
2464b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1;
2465b7e1c893Smrg	else
2466b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_TMDS1;
2467b7e1c893Smrg	break;
2468b7e1c893Smrg    case ATOM_DEVICE_LCD2_SUPPORT:
2469b7e1c893Smrg    case ATOM_DEVICE_DFP2_SUPPORT:
2470b7e1c893Smrg	if ((info->ChipFamily == CHIP_FAMILY_RS600) ||
2471b7e1c893Smrg	    (info->ChipFamily == CHIP_FAMILY_RS690) ||
2472b7e1c893Smrg	    (info->ChipFamily == CHIP_FAMILY_RS740))
2473b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_DDI;
2474b7e1c893Smrg	else if (IS_AVIVO_VARIANT)
2475b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
2476b7e1c893Smrg	else
2477b7e1c893Smrg	    ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
2478b7e1c893Smrg	break;
2479b7e1c893Smrg    case ATOM_DEVICE_DFP3_SUPPORT:
2480b7e1c893Smrg	ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
2481b7e1c893Smrg	break;
2482209ff23fSmrg    }
2483209ff23fSmrg
2484b7e1c893Smrg    return ret;
2485209ff23fSmrg}
2486209ff23fSmrg
2487209ff23fSmrgBool
2488209ff23fSmrgRADEONGetATOMConnectorInfoFromBIOSConnectorTable (ScrnInfoPtr pScrn)
2489209ff23fSmrg{
2490209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (pScrn);
2491209ff23fSmrg    atomDataTablesPtr atomDataPtr;
2492209ff23fSmrg    uint8_t crev, frev;
2493209ff23fSmrg    int i, j;
2494b7e1c893Smrg    Bool enable_tv = FALSE;
2495b7e1c893Smrg
2496b7e1c893Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_ATOM_TVOUT, FALSE))
2497b7e1c893Smrg	enable_tv = TRUE;
2498209ff23fSmrg
2499209ff23fSmrg    atomDataPtr = info->atomBIOS->atomDataPtr;
2500209ff23fSmrg
2501209ff23fSmrg    if (!rhdAtomGetTableRevisionAndSize(
2502209ff23fSmrg	    &(atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->sHeader),
2503209ff23fSmrg	    &crev,&frev,NULL)) {
2504209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Device Info Table found!\n");
2505209ff23fSmrg	return FALSE;
2506209ff23fSmrg    }
2507209ff23fSmrg
2508209ff23fSmrg    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2509209ff23fSmrg	ATOM_CONNECTOR_INFO_I2C ci
2510209ff23fSmrg	    = atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->asConnInfo[i];
2511209ff23fSmrg
2512209ff23fSmrg	if (!(le16_to_cpu(atomDataPtr->SupportedDevicesInfo
2513209ff23fSmrg			  .SupportedDevicesInfo->usDeviceSupport) & (1 << i))) {
2514209ff23fSmrg	    info->BiosConnector[i].valid = FALSE;
2515209ff23fSmrg	    continue;
2516209ff23fSmrg	}
2517209ff23fSmrg
2518b7e1c893Smrg	/* don't support CV yet */
2519209ff23fSmrg	if (i == ATOM_DEVICE_CV_INDEX) {
2520209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Skipping Component Video\n");
2521209ff23fSmrg	    info->BiosConnector[i].valid = FALSE;
2522209ff23fSmrg	    continue;
2523209ff23fSmrg	}
2524b7e1c893Smrg
2525b7e1c893Smrg	if (!enable_tv && (i == ATOM_DEVICE_TV1_INDEX)) {
2526209ff23fSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Skipping TV-Out\n");
2527209ff23fSmrg	    info->BiosConnector[i].valid = FALSE;
2528209ff23fSmrg	    continue;
2529209ff23fSmrg	}
2530209ff23fSmrg
2531209ff23fSmrg	info->BiosConnector[i].valid = TRUE;
2532b7e1c893Smrg	info->BiosConnector[i].load_detection = TRUE;
2533b7e1c893Smrg	info->BiosConnector[i].shared_ddc = FALSE;
2534ad43ddacSmrg	info->BiosConnector[i].output_id = ci.sucI2cId.ucAccess;
2535209ff23fSmrg	info->BiosConnector[i].devices = (1 << i);
2536209ff23fSmrg	info->BiosConnector[i].ConnectorType = ci.sucConnectorInfo.sbfAccess.bfConnectorType;
2537209ff23fSmrg
2538209ff23fSmrg	if (info->BiosConnector[i].ConnectorType == CONNECTOR_NONE) {
2539209ff23fSmrg	    info->BiosConnector[i].valid = FALSE;
2540209ff23fSmrg	    continue;
2541209ff23fSmrg	}
2542209ff23fSmrg
2543209ff23fSmrg	/* don't assign a gpio for tv */
2544209ff23fSmrg	if ((i == ATOM_DEVICE_TV1_INDEX) ||
2545209ff23fSmrg	    (i == ATOM_DEVICE_TV2_INDEX) ||
2546209ff23fSmrg	    (i == ATOM_DEVICE_CV_INDEX))
2547209ff23fSmrg	    info->BiosConnector[i].ddc_i2c.valid = FALSE;
2548ad43ddacSmrg	else
2549209ff23fSmrg	    info->BiosConnector[i].ddc_i2c =
2550ad43ddacSmrg		RADEONLookupGPIOLineForDDC(pScrn, ci.sucI2cId.ucAccess);
2551209ff23fSmrg
2552b7e1c893Smrg	if (!radeon_add_encoder(pScrn,
2553b7e1c893Smrg			   radeon_get_encoder_id_from_supported_device(pScrn, (1 << i),
2554b7e1c893Smrg					  ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC),
2555b7e1c893Smrg				(1 << i)))
2556b7e1c893Smrg	    return FALSE;
2557209ff23fSmrg
2558209ff23fSmrg	/* Always set the connector type to VGA for CRT1/CRT2. if they are
2559209ff23fSmrg	 * shared with a DVI port, we'll pick up the DVI connector below when we
2560209ff23fSmrg	 * merge the outputs
2561209ff23fSmrg	 */
2562209ff23fSmrg	if ((i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) &&
2563209ff23fSmrg	    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I ||
2564209ff23fSmrg	     info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D ||
2565209ff23fSmrg	     info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A)) {
2566209ff23fSmrg	    info->BiosConnector[i].ConnectorType = CONNECTOR_VGA;
2567209ff23fSmrg	}
2568209ff23fSmrg
2569209ff23fSmrg	if (crev > 1) {
2570209ff23fSmrg	    ATOM_CONNECTOR_INC_SRC_BITMAP isb
2571209ff23fSmrg		= atomDataPtr->SupportedDevicesInfo
2572209ff23fSmrg		.SupportedDevicesInfo_HD->asIntSrcInfo[i];
2573209ff23fSmrg
2574209ff23fSmrg	    switch (isb.ucIntSrcBitmap) {
2575209ff23fSmrg		case 0x4:
2576209ff23fSmrg		    info->BiosConnector[i].hpd_mask = 0x00000001;
2577209ff23fSmrg		    break;
2578209ff23fSmrg		case 0xa:
2579209ff23fSmrg		    info->BiosConnector[i].hpd_mask = 0x00000100;
2580209ff23fSmrg		    break;
2581209ff23fSmrg		default:
2582209ff23fSmrg		    info->BiosConnector[i].hpd_mask = 0;
2583209ff23fSmrg		    break;
2584209ff23fSmrg	    }
2585b7e1c893Smrg	} else
2586209ff23fSmrg	    info->BiosConnector[i].hpd_mask = 0;
2587209ff23fSmrg
2588209ff23fSmrg	RADEONApplyATOMQuirks(pScrn, i);
2589209ff23fSmrg
2590209ff23fSmrg    }
2591209ff23fSmrg
2592209ff23fSmrg    /* CRTs/DFPs may share a port */
2593209ff23fSmrg    for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
2594209ff23fSmrg	if (info->BiosConnector[i].valid) {
2595209ff23fSmrg	    for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
2596209ff23fSmrg		if (info->BiosConnector[j].valid && (i != j) ) {
2597209ff23fSmrg		    if (info->BiosConnector[i].output_id == info->BiosConnector[j].output_id) {
2598209ff23fSmrg			if (((i == ATOM_DEVICE_DFP1_INDEX) ||
2599209ff23fSmrg			     (i == ATOM_DEVICE_DFP2_INDEX) ||
2600209ff23fSmrg			     (i == ATOM_DEVICE_DFP3_INDEX)) &&
2601b7e1c893Smrg			    ((j == ATOM_DEVICE_CRT1_INDEX) ||
2602b7e1c893Smrg			     (j == ATOM_DEVICE_CRT2_INDEX))) {
2603209ff23fSmrg			    info->BiosConnector[i].devices |= info->BiosConnector[j].devices;
2604c503f109Smrg			    if (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D)
2605c503f109Smrg				info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_I;
2606209ff23fSmrg			    info->BiosConnector[j].valid = FALSE;
2607209ff23fSmrg			} else if (((j == ATOM_DEVICE_DFP1_INDEX) ||
2608b7e1c893Smrg				    (j == ATOM_DEVICE_DFP2_INDEX) ||
2609b7e1c893Smrg				    (j == ATOM_DEVICE_DFP3_INDEX)) &&
2610b7e1c893Smrg				   ((i == ATOM_DEVICE_CRT1_INDEX) ||
2611b7e1c893Smrg				    (i == ATOM_DEVICE_CRT2_INDEX))) {
2612209ff23fSmrg			    info->BiosConnector[j].devices |= info->BiosConnector[i].devices;
2613c503f109Smrg			    if (info->BiosConnector[j].ConnectorType == CONNECTOR_DVI_D)
2614c503f109Smrg				info->BiosConnector[j].ConnectorType = CONNECTOR_DVI_I;
2615209ff23fSmrg			    info->BiosConnector[i].valid = FALSE;
2616b7e1c893Smrg			} else {
2617b7e1c893Smrg			    info->BiosConnector[i].shared_ddc = TRUE;
2618b7e1c893Smrg			    info->BiosConnector[j].shared_ddc = TRUE;
2619209ff23fSmrg			}
2620209ff23fSmrg			/* other possible combos?  */
2621209ff23fSmrg		    }
2622209ff23fSmrg		}
2623209ff23fSmrg	    }
2624209ff23fSmrg	}
2625209ff23fSmrg    }
2626209ff23fSmrg
2627209ff23fSmrg    return TRUE;
2628209ff23fSmrg}
2629209ff23fSmrg
2630209ff23fSmrg# ifdef ATOM_BIOS_PARSER
2631209ff23fSmrgstatic AtomBiosResult
2632209ff23fSmrgrhdAtomExec (atomBiosHandlePtr handle,
2633209ff23fSmrg	     AtomBiosRequestID unused, AtomBiosArgPtr data)
2634209ff23fSmrg{
2635209ff23fSmrg    RADEONInfoPtr info = RADEONPTR (xf86Screens[handle->scrnIndex]);
2636209ff23fSmrg    Bool ret = FALSE;
2637209ff23fSmrg    char *msg;
2638209ff23fSmrg    int idx = data->exec.index;
2639209ff23fSmrg    void *pspace = data->exec.pspace;
2640209ff23fSmrg    pointer *dataSpace = data->exec.dataSpace;
2641209ff23fSmrg
2642209ff23fSmrg    //RHDFUNCI(handle->scrnIndex);
2643209ff23fSmrg
2644209ff23fSmrg    if (dataSpace) {
2645209ff23fSmrg	if (!handle->fbBase && !handle->scratchBase)
2646209ff23fSmrg	    return ATOM_FAILED;
2647209ff23fSmrg	if (handle->fbBase) {
2648209ff23fSmrg	    if (!info->FB) {
2649209ff23fSmrg		xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: "
2650209ff23fSmrg			   "Cannot exec AtomBIOS: framebuffer not mapped\n",
2651209ff23fSmrg			   __func__);
2652209ff23fSmrg		return ATOM_FAILED;
2653209ff23fSmrg	    }
2654209ff23fSmrg	    *dataSpace = (uint8_t*)info->FB + handle->fbBase;
2655209ff23fSmrg	} else
2656209ff23fSmrg	    *dataSpace = (uint8_t*)handle->scratchBase;
2657209ff23fSmrg    }
2658209ff23fSmrg    ret = ParseTableWrapper(pspace, idx, handle,
2659209ff23fSmrg			    handle->BIOSBase,
2660209ff23fSmrg			    &msg);
2661209ff23fSmrg    if (!ret)
2662209ff23fSmrg	xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s\n",msg);
2663209ff23fSmrg    else
2664209ff23fSmrg	xf86DrvMsgVerb(handle->scrnIndex, X_INFO, 5, "%s\n",msg);
2665209ff23fSmrg
2666209ff23fSmrg    return (ret) ? ATOM_SUCCESS : ATOM_FAILED;
2667209ff23fSmrg}
2668209ff23fSmrg# endif
2669209ff23fSmrg
2670209ff23fSmrgAtomBiosResult
2671209ff23fSmrgRHDAtomBiosFunc(int scrnIndex, atomBiosHandlePtr handle,
2672209ff23fSmrg		AtomBiosRequestID id, AtomBiosArgPtr data)
2673209ff23fSmrg{
2674209ff23fSmrg    AtomBiosResult ret = ATOM_FAILED;
2675209ff23fSmrg    int i;
2676209ff23fSmrg    char *msg = NULL;
2677209ff23fSmrg    enum msgDataFormat msg_f = MSG_FORMAT_NONE;
2678209ff23fSmrg    AtomBiosRequestFunc req_func = NULL;
2679209ff23fSmrg
2680209ff23fSmrg    //RHDFUNCI(scrnIndex);
2681209ff23fSmrg
2682209ff23fSmrg    for (i = 0; AtomBiosRequestList[i].id != FUNC_END; i++) {
2683209ff23fSmrg	if (id ==  AtomBiosRequestList[i].id) {
2684209ff23fSmrg	    req_func = AtomBiosRequestList[i].request;
2685209ff23fSmrg	    msg = AtomBiosRequestList[i].message;
2686209ff23fSmrg	    msg_f = AtomBiosRequestList[i].message_format;
2687209ff23fSmrg	    break;
2688209ff23fSmrg	}
2689209ff23fSmrg    }
2690209ff23fSmrg
2691209ff23fSmrg    if (req_func == NULL) {
2692209ff23fSmrg	xf86DrvMsg(scrnIndex, X_ERROR, "Unknown AtomBIOS request: %i\n",id);
2693209ff23fSmrg	return ATOM_NOT_IMPLEMENTED;
2694209ff23fSmrg    }
2695209ff23fSmrg    /* Hack for now */
2696209ff23fSmrg    if (id == ATOMBIOS_INIT)
2697209ff23fSmrg	data->val = scrnIndex;
2698209ff23fSmrg
2699209ff23fSmrg    if (id == ATOMBIOS_INIT || handle)
2700209ff23fSmrg	ret = req_func(handle, id, data);
2701209ff23fSmrg
2702209ff23fSmrg    if (ret == ATOM_SUCCESS) {
2703209ff23fSmrg
2704209ff23fSmrg	switch (msg_f) {
2705209ff23fSmrg	    case MSG_FORMAT_DEC:
2706209ff23fSmrg		xf86DrvMsg(scrnIndex,X_INFO,"%s: %li\n", msg,
2707209ff23fSmrg			   (unsigned long) data->val);
2708209ff23fSmrg		break;
2709209ff23fSmrg	    case MSG_FORMAT_HEX:
2710209ff23fSmrg		xf86DrvMsg(scrnIndex,X_INFO,"%s: 0x%lx\n",msg ,
2711209ff23fSmrg			   (unsigned long) data->val);
2712209ff23fSmrg		break;
2713209ff23fSmrg	    case MSG_FORMAT_NONE:
2714209ff23fSmrg		xf86DrvMsgVerb(scrnIndex, 7, X_INFO,
2715209ff23fSmrg			       "Call to %s succeeded\n", msg);
2716209ff23fSmrg		break;
2717209ff23fSmrg	}
2718209ff23fSmrg
2719209ff23fSmrg    } else {
2720209ff23fSmrg
2721209ff23fSmrg	char *result = (ret == ATOM_FAILED) ? "failed"
2722209ff23fSmrg	    : "not implemented";
2723209ff23fSmrg	switch (msg_f) {
2724209ff23fSmrg	    case MSG_FORMAT_DEC:
2725209ff23fSmrg	    case MSG_FORMAT_HEX:
2726209ff23fSmrg		xf86DrvMsgVerb(scrnIndex, 1, X_WARNING,
2727209ff23fSmrg			       "Call to %s %s\n", msg, result);
2728209ff23fSmrg		break;
2729209ff23fSmrg	    case MSG_FORMAT_NONE:
2730209ff23fSmrg		xf86DrvMsg(scrnIndex,X_INFO,"Query for %s: %s\n", msg, result);
2731209ff23fSmrg		    break;
2732209ff23fSmrg	}
2733209ff23fSmrg    }
2734209ff23fSmrg    return ret;
2735209ff23fSmrg}
2736209ff23fSmrg
2737209ff23fSmrg# ifdef ATOM_BIOS_PARSER
2738209ff23fSmrgVOID*
2739209ff23fSmrgCailAllocateMemory(VOID *CAIL,UINT16 size)
2740209ff23fSmrg{
2741b7e1c893Smrg    void *ret;
2742209ff23fSmrg    CAILFUNC(CAIL);
2743209ff23fSmrg
2744b7e1c893Smrg    ret = malloc(size);
2745b7e1c893Smrg    memset(ret, 0, size);
2746b7e1c893Smrg    return ret;
2747209ff23fSmrg}
2748209ff23fSmrg
2749209ff23fSmrgVOID
2750209ff23fSmrgCailReleaseMemory(VOID *CAIL, VOID *addr)
2751209ff23fSmrg{
2752209ff23fSmrg    CAILFUNC(CAIL);
2753209ff23fSmrg
2754209ff23fSmrg    free(addr);
2755209ff23fSmrg}
2756209ff23fSmrg
2757209ff23fSmrgVOID
2758209ff23fSmrgCailDelayMicroSeconds(VOID *CAIL, UINT32 delay)
2759209ff23fSmrg{
2760209ff23fSmrg    CAILFUNC(CAIL);
2761209ff23fSmrg
2762209ff23fSmrg    usleep(delay);
2763209ff23fSmrg
2764209ff23fSmrg    /*DEBUGP(xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_INFO,"Delay %i usec\n",delay));*/
2765209ff23fSmrg}
2766209ff23fSmrg
2767209ff23fSmrgUINT32
2768209ff23fSmrgCailReadATIRegister(VOID* CAIL, UINT32 idx)
2769209ff23fSmrg{
2770209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2771ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
2772209ff23fSmrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2773209ff23fSmrg    unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
2774209ff23fSmrg    UINT32 ret;
2775ad43ddacSmrg    UINT32 mm_reg = idx << 2;
2776209ff23fSmrg    CAILFUNC(CAIL);
2777209ff23fSmrg
2778ad43ddacSmrg    if (mm_reg < info->MMIOSize)
2779ad43ddacSmrg	ret = INREG(mm_reg);
2780ad43ddacSmrg    else {
2781ad43ddacSmrg	OUTREG(RADEON_MM_INDEX, mm_reg);
2782ad43ddacSmrg	ret = INREG(RADEON_MM_DATA);
2783ad43ddacSmrg    }
2784ad43ddacSmrg
2785209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx << 2,ret));*/
2786209ff23fSmrg    return ret;
2787209ff23fSmrg}
2788209ff23fSmrg
2789209ff23fSmrgVOID
2790209ff23fSmrgCailWriteATIRegister(VOID *CAIL, UINT32 idx, UINT32 data)
2791209ff23fSmrg{
2792209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2793ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
2794209ff23fSmrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2795209ff23fSmrg    unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
2796ad43ddacSmrg    UINT32 mm_reg = idx << 2;
2797209ff23fSmrg    CAILFUNC(CAIL);
2798209ff23fSmrg
2799ad43ddacSmrg    if (mm_reg < info->MMIOSize)
2800ad43ddacSmrg	OUTREG(mm_reg, data);
2801ad43ddacSmrg    else {
2802ad43ddacSmrg	OUTREG(RADEON_MM_INDEX, mm_reg);
2803ad43ddacSmrg	OUTREG(RADEON_MM_DATA, data);
2804ad43ddacSmrg    }
2805ad43ddacSmrg
2806209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx << 2,data));*/
2807209ff23fSmrg}
2808209ff23fSmrg
2809209ff23fSmrgUINT32
2810209ff23fSmrgCailReadFBData(VOID* CAIL, UINT32 idx)
2811209ff23fSmrg{
2812209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2813209ff23fSmrg    RADEONInfoPtr  info   = RADEONPTR(pScrn);
2814209ff23fSmrg    UINT32 ret;
2815209ff23fSmrg
2816209ff23fSmrg    CAILFUNC(CAIL);
2817209ff23fSmrg
2818209ff23fSmrg    if (((atomBiosHandlePtr)CAIL)->fbBase) {
2819209ff23fSmrg	uint8_t *FBBase = (uint8_t*)info->FB;
2820209ff23fSmrg	ret =  *((uint32_t*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx));
2821209ff23fSmrg	/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,ret));*/
2822209ff23fSmrg    } else if (((atomBiosHandlePtr)CAIL)->scratchBase) {
2823209ff23fSmrg	ret = *(uint32_t*)((uint8_t*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx);
2824209ff23fSmrg	/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,ret));*/
2825209ff23fSmrg    } else {
2826209ff23fSmrg	xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
2827209ff23fSmrg		   "%s: no fbbase set\n",__func__);
2828209ff23fSmrg	return 0;
2829209ff23fSmrg    }
2830209ff23fSmrg    return ret;
2831209ff23fSmrg}
2832209ff23fSmrg
2833209ff23fSmrgVOID
2834209ff23fSmrgCailWriteFBData(VOID *CAIL, UINT32 idx, UINT32 data)
2835209ff23fSmrg{
2836209ff23fSmrg    CAILFUNC(CAIL);
2837209ff23fSmrg
2838209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx,data));*/
2839209ff23fSmrg    if (((atomBiosHandlePtr)CAIL)->fbBase) {
2840209ff23fSmrg	uint8_t *FBBase = (uint8_t*)
2841209ff23fSmrg	    RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->FB;
2842209ff23fSmrg	*((uint32_t*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx)) = data;
2843209ff23fSmrg    } else if (((atomBiosHandlePtr)CAIL)->scratchBase) {
2844209ff23fSmrg	*(uint32_t*)((uint8_t*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx) = data;
2845209ff23fSmrg    } else
2846209ff23fSmrg	xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
2847209ff23fSmrg		   "%s: no fbbase set\n",__func__);
2848209ff23fSmrg}
2849209ff23fSmrg
2850209ff23fSmrgULONG
2851209ff23fSmrgCailReadMC(VOID *CAIL, ULONG Address)
2852209ff23fSmrg{
2853209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2854209ff23fSmrg    ULONG ret;
2855209ff23fSmrg
2856209ff23fSmrg    CAILFUNC(CAIL);
2857209ff23fSmrg
2858209ff23fSmrg    ret = INMC(pScrn, Address);
2859209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,Address,ret));*/
2860209ff23fSmrg    return ret;
2861209ff23fSmrg}
2862209ff23fSmrg
2863209ff23fSmrgVOID
2864209ff23fSmrgCailWriteMC(VOID *CAIL, ULONG Address, ULONG data)
2865209ff23fSmrg{
2866209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2867209ff23fSmrg
2868209ff23fSmrg    CAILFUNC(CAIL);
2869209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,Address,data));*/
2870209ff23fSmrg    OUTMC(pScrn, Address, data);
2871209ff23fSmrg}
2872209ff23fSmrg
2873209ff23fSmrg#ifdef XSERVER_LIBPCIACCESS
2874209ff23fSmrg
2875209ff23fSmrgVOID
2876209ff23fSmrgCailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size)
2877209ff23fSmrg{
2878209ff23fSmrg    pci_device_cfg_read(RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->PciInfo,
2879209ff23fSmrg				ret,idx << 2 , size >> 3, NULL);
2880209ff23fSmrg}
2881209ff23fSmrg
2882209ff23fSmrgVOID
2883209ff23fSmrgCailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size)
2884209ff23fSmrg{
2885209ff23fSmrg    pci_device_cfg_write(RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->PciInfo,
2886209ff23fSmrg			 src, idx << 2, size >> 3, NULL);
2887209ff23fSmrg}
2888209ff23fSmrg
2889209ff23fSmrg#else
2890209ff23fSmrg
2891209ff23fSmrgVOID
2892209ff23fSmrgCailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size)
2893209ff23fSmrg{
2894209ff23fSmrg    PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag;
2895209ff23fSmrg
2896209ff23fSmrg    CAILFUNC(CAIL);
2897209ff23fSmrg
2898209ff23fSmrg    switch (size) {
2899209ff23fSmrg	case 8:
2900209ff23fSmrg	    *(uint8_t*)ret = pciReadByte(tag,idx << 2);
2901209ff23fSmrg	    break;
2902209ff23fSmrg	case 16:
2903209ff23fSmrg	    *(uint16_t*)ret = pciReadWord(tag,idx << 2);
2904209ff23fSmrg	    break;
2905209ff23fSmrg	case 32:
2906209ff23fSmrg	    *(uint32_t*)ret = pciReadLong(tag,idx << 2);
2907209ff23fSmrg	    break;
2908209ff23fSmrg	default:
2909209ff23fSmrg	xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,
2910209ff23fSmrg		   X_ERROR,"%s: Unsupported size: %i\n",
2911209ff23fSmrg		   __func__,(int)size);
2912209ff23fSmrg	return;
2913209ff23fSmrg	    break;
2914209ff23fSmrg    }
2915209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,*(unsigned int*)ret));*/
2916209ff23fSmrg
2917209ff23fSmrg}
2918209ff23fSmrg
2919209ff23fSmrgVOID
2920209ff23fSmrgCailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size)
2921209ff23fSmrg{
2922209ff23fSmrg    PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag;
2923209ff23fSmrg
2924209ff23fSmrg    CAILFUNC(CAIL);
2925209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx,(*(unsigned int*)src)));*/
2926209ff23fSmrg    switch (size) {
2927209ff23fSmrg	case 8:
2928209ff23fSmrg	    pciWriteByte(tag,idx << 2,*(uint8_t*)src);
2929209ff23fSmrg	    break;
2930209ff23fSmrg	case 16:
2931209ff23fSmrg	    pciWriteWord(tag,idx << 2,*(uint16_t*)src);
2932209ff23fSmrg	    break;
2933209ff23fSmrg	case 32:
2934209ff23fSmrg	    pciWriteLong(tag,idx << 2,*(uint32_t*)src);
2935209ff23fSmrg	    break;
2936209ff23fSmrg	default:
2937209ff23fSmrg	    xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
2938209ff23fSmrg		       "%s: Unsupported size: %i\n",__func__,(int)size);
2939209ff23fSmrg	    break;
2940209ff23fSmrg    }
2941209ff23fSmrg}
2942209ff23fSmrg#endif
2943209ff23fSmrg
2944209ff23fSmrgULONG
2945209ff23fSmrgCailReadPLL(VOID *CAIL, ULONG Address)
2946209ff23fSmrg{
2947209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2948209ff23fSmrg    ULONG ret;
2949209ff23fSmrg
2950209ff23fSmrg    CAILFUNC(CAIL);
2951209ff23fSmrg
2952209ff23fSmrg    ret = RADEONINPLL(pScrn, Address);
2953209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,Address,ret));*/
2954209ff23fSmrg    return ret;
2955209ff23fSmrg}
2956209ff23fSmrg
2957209ff23fSmrgVOID
2958209ff23fSmrgCailWritePLL(VOID *CAIL, ULONG Address,ULONG Data)
2959209ff23fSmrg{
2960209ff23fSmrg    ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
2961209ff23fSmrg    CAILFUNC(CAIL);
2962209ff23fSmrg
2963209ff23fSmrg    /*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,Address,Data));*/
2964209ff23fSmrg    RADEONOUTPLL(pScrn, Address, Data);
2965209ff23fSmrg}
2966209ff23fSmrg
2967209ff23fSmrgvoid
2968209ff23fSmrgatombios_get_command_table_version(atomBiosHandlePtr atomBIOS, int index, int *major, int *minor)
2969209ff23fSmrg{
2970209ff23fSmrg    ATOM_MASTER_COMMAND_TABLE *cmd_table = (void *)(atomBIOS->BIOSBase + atomBIOS->cmd_offset);
2971209ff23fSmrg    ATOM_MASTER_LIST_OF_COMMAND_TABLES *table_start;
2972209ff23fSmrg    ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *table_hdr;
2973209ff23fSmrg
2974209ff23fSmrg    //unsigned short *ptr;
2975209ff23fSmrg    unsigned short offset;
2976209ff23fSmrg
2977209ff23fSmrg    table_start = &cmd_table->ListOfCommandTables;
2978209ff23fSmrg
2979209ff23fSmrg    offset  = *(((unsigned short *)table_start) + index);
2980209ff23fSmrg
2981209ff23fSmrg    offset = le16_to_cpu(offset);
2982209ff23fSmrg    table_hdr = (ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *)(atomBIOS->BIOSBase + offset);
2983209ff23fSmrg
2984209ff23fSmrg    *major = table_hdr->CommonHeader.ucTableFormatRevision;
2985209ff23fSmrg    *minor = table_hdr->CommonHeader.ucTableContentRevision;
2986209ff23fSmrg}
2987209ff23fSmrg
2988209ff23fSmrg
2989b7e1c893SmrgUINT16 ATOM_BSWAP16(UINT16 x)
2990b7e1c893Smrg{
2991b7e1c893Smrg    return bswap_16(x);
2992b7e1c893Smrg}
2993b7e1c893Smrg
2994b7e1c893SmrgUINT32 ATOM_BSWAP32(UINT32 x)
2995b7e1c893Smrg{
2996b7e1c893Smrg    return bswap_32(x);
2997b7e1c893Smrg}
2998b7e1c893Smrg
2999b7e1c893Smrg
3000209ff23fSmrg#endif /* ATOM_BIOS */
3001