1/*
2 * Copyright 2006-2007 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23/**
24
25Module Name:
26
27    Decoder.c
28
29Abstract:
30
31		Commands Decoder
32
33Revision History:
34
35	NEG:24.09.2002	Initiated.
36--*/
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42#include <X11/Xos.h>
43#include "xorg-server.h"
44
45#include "Decoder.h"
46
47#ifndef DISABLE_EASF
48	#include "easf.h"
49#endif
50
51
52
53#define INDIRECT_IO_TABLE (((UINT16)(ULONG_PTR)&((ATOM_MASTER_LIST_OF_DATA_TABLES*)0)->IndirectIOAccess)/sizeof(TABLE_UNIT_TYPE) )
54extern COMMANDS_PROPERTIES CallTable[];
55
56
57UINT8 ProcessCommandProperties(PARSER_TEMP_DATA STACK_BASED *	pParserTempData)
58{
59  UINT8 opcode=((COMMAND_HEADER*)pParserTempData->pWorkingTableData->IP)->Opcode;
60  pParserTempData->pWorkingTableData->IP+=CallTable[opcode].headersize;
61  pParserTempData->ParametersType.Destination=CallTable[opcode].destination;
62  pParserTempData->ParametersType.Source = pParserTempData->pCmd->Header.Attribute.Source;
63  pParserTempData->CD_Mask.SrcAlignment=pParserTempData->pCmd->Header.Attribute.SourceAlignment;
64  pParserTempData->CD_Mask.DestAlignment=pParserTempData->pCmd->Header.Attribute.DestinationAlignment;
65  return opcode;
66}
67
68UINT16* GetCommandMasterTablePointer(DEVICE_DATA STACK_BASED*  pDeviceData)
69{
70	UINT16		*MasterTableOffset;
71#ifndef DISABLE_EASF
72	if (pDeviceData->format == TABLE_FORMAT_EASF)
73	{
74    /*
75    make MasterTableOffset point to EASF_ASIC_SETUP_TABLE structure, including usSize.
76    */
77		MasterTableOffset = (UINT16 *) (pDeviceData->pBIOS_Image+(UINT16LE_TO_CPU(((EASF_ASIC_DESCRIPTOR*)pDeviceData->pBIOS_Image)->usAsicSetupTable_Offset));
78	} else
79#endif
80	{
81#ifndef		UEFI_BUILD
82		MasterTableOffset = (UINT16 *)(UINT16LE_TO_CPU(*(UINT16 *)(pDeviceData->pBIOS_Image+OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER)) + pDeviceData->pBIOS_Image);
83		MasterTableOffset = (UINT16 *)((ULONG)UINT16LE_TO_CPU(((ATOM_ROM_HEADER *)MasterTableOffset)->usMasterCommandTableOffset) + pDeviceData->pBIOS_Image );
84		MasterTableOffset =(UINT16 *) &(((ATOM_MASTER_COMMAND_TABLE *)MasterTableOffset)->ListOfCommandTables);
85#else
86	MasterTableOffset = (UINT16 *)(&(GetCommandMasterTable( )->ListOfCommandTables));
87#endif
88	}
89	return MasterTableOffset;
90}
91
92UINT16* GetDataMasterTablePointer(DEVICE_DATA STACK_BASED*  pDeviceData)
93{
94	UINT16		*MasterTableOffset;
95
96#ifndef		UEFI_BUILD
97	MasterTableOffset = (UINT16 *)(UINT16LE_TO_CPU(*(UINT16 *)(pDeviceData->pBIOS_Image+OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER)) + pDeviceData->pBIOS_Image);
98	MasterTableOffset = (UINT16 *)((ULONG)(UINT16LE_TO_CPU(((ATOM_ROM_HEADER *)MasterTableOffset)->usMasterDataTableOffset)) + pDeviceData->pBIOS_Image );
99	MasterTableOffset =(UINT16 *) &(((ATOM_MASTER_DATA_TABLE *)MasterTableOffset)->ListOfDataTables);
100#else
101	MasterTableOffset = (UINT16 *)(&(GetDataMasterTable( )->ListOfDataTables));
102#endif
103	return MasterTableOffset;
104}
105
106
107UINT8 GetTrueIndexInMasterTable(PARSER_TEMP_DATA STACK_BASED * pParserTempData, UINT8 IndexInMasterTable)
108{
109#ifndef DISABLE_EASF
110	UINT16 i;
111	if ( pParserTempData->pDeviceData->format == TABLE_FORMAT_EASF)
112	{
113/*
114		Consider EASF_ASIC_SETUP_TABLE structure pointed by pParserTempData->pCmd as UINT16[]
115		((UINT16*)pParserTempData->pCmd)[0] = EASF_ASIC_SETUP_TABLE.usSize;
116		((UINT16*)pParserTempData->pCmd)[1+n*4] = usFunctionID;
117		usFunctionID has to be shifted left by 2 before compare it to the value provided by caller.
118*/
119		for (i=1; (i < ((UINT16*)pParserTempData->pCmd)[0] >> 1);i+=4)
120	  		if ((UINT8)(((UINT16*)pParserTempData->pCmd)[i] << 2)==(IndexInMasterTable & EASF_TABLE_INDEX_MASK)) return (i+1+(IndexInMasterTable & EASF_TABLE_ATTR_MASK));
121		return 1;
122	} else
123#endif
124	{
125		return IndexInMasterTable;
126	}
127}
128
129ATOM_TABLE_ATTRIBUTE GetCommandTableAttribute(UINT8 *pTableHeader)
130{
131  ATOM_TABLE_ATTRIBUTE_ACCESS lTableAccess;
132
133  /* It's unclear whether this union trick breaks C aliasing rules,
134   * however, it's explicitely permitted by gcc, and we have other
135   * case where the code relies on a union being accessed by either
136   * of the "ways" and stay consistent so if a compiler breaks this
137   * assumption, it will probably need us to compile without strict
138   * aliasing enforcement
139	 */
140	lTableAccess.sbfAccess = ((ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *)pTableHeader)->TableAttribute;
141	lTableAccess.susAccess = UINT16LE_TO_CPU(lTableAccess.susAccess);
142
143	return lTableAccess.sbfAccess;
144}
145
146CD_STATUS ParseTable(DEVICE_DATA STACK_BASED* pDeviceData, UINT8 IndexInMasterTable)
147{
148	PARSER_TEMP_DATA	ParserTempData;
149  WORKING_TABLE_DATA STACK_BASED* prevWorkingTableData;
150
151  memset(&ParserTempData, 0, sizeof(PARSER_TEMP_DATA));
152  ParserTempData.pDeviceData=(DEVICE_DATA*)pDeviceData;
153#ifndef DISABLE_EASF
154  if (pDeviceData->format == TABLE_FORMAT_EASF)
155  {
156      ParserTempData.IndirectIOTablePointer = 0;
157  } else
158#endif
159  {
160    ParserTempData.pCmd=(GENERIC_ATTRIBUTE_COMMAND*)GetDataMasterTablePointer(pDeviceData);
161    ParserTempData.IndirectIOTablePointer=(UINT8*)((ULONG)(UINT16LE_TO_CPU(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[INDIRECT_IO_TABLE])) + pDeviceData->pBIOS_Image);
162    ParserTempData.IndirectIOTablePointer+=sizeof(ATOM_COMMON_TABLE_HEADER);
163  }
164
165	ParserTempData.pCmd=(GENERIC_ATTRIBUTE_COMMAND*)GetCommandMasterTablePointer(pDeviceData);
166    IndexInMasterTable=GetTrueIndexInMasterTable((PARSER_TEMP_DATA STACK_BASED *)&ParserTempData,IndexInMasterTable);
167	if(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable]!=0 )  // if the offset is not ZERO
168	{
169		ParserTempData.CommandSpecific.IndexInMasterTable=IndexInMasterTable;
170		ParserTempData.Multipurpose.CurrentPort=ATI_RegsPort;
171		ParserTempData.CurrentPortID=INDIRECT_IO_MM;
172		ParserTempData.CurrentRegBlock=0;
173		ParserTempData.CurrentFB_Window=0;
174    prevWorkingTableData=NULL;
175		ParserTempData.Status=CD_CALL_TABLE;
176
177		do{
178
179			if (ParserTempData.Status==CD_CALL_TABLE)
180			{
181				IndexInMasterTable=ParserTempData.CommandSpecific.IndexInMasterTable;
182				if(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable]!=0)  // if the offset is not ZERO
183				{
184				  ATOM_TABLE_ATTRIBUTE lTableAttr;
185				  lTableAttr = GetCommandTableAttribute(UINT16LE_TO_CPU(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable])+pDeviceData->pBIOS_Image);
186#ifndef		UEFI_BUILD
187  					ParserTempData.pWorkingTableData =(WORKING_TABLE_DATA STACK_BASED*) AllocateWorkSpace(pDeviceData,
188															      lTableAttr.WS_SizeInBytes+sizeof(WORKING_TABLE_DATA));
189#else
190				  ParserTempData.pWorkingTableData =(WORKING_TABLE_DATA STACK_BASED*) AllocateWorkSpace(pDeviceData,
191															lTableAttr.WS_SizeInBytes+sizeof(WORKING_TABLE_DATA));
192#endif
193					if (ParserTempData.pWorkingTableData!=NULL)
194					{
195						ParserTempData.pWorkingTableData->pWorkSpace=(WORKSPACE_POINTER STACK_BASED*)((UINT8*)ParserTempData.pWorkingTableData+sizeof(WORKING_TABLE_DATA));
196#ifndef		UEFI_BUILD
197				      ParserTempData.pWorkingTableData->pTableHead  = (UINT8 *)(UINT16LE_TO_CPU(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable])+pDeviceData->pBIOS_Image);
198#else
199				      ParserTempData.pWorkingTableData->pTableHead  = (UINT8 *)(UINT16LE_TO_CPU(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable]));
200#endif
201						ParserTempData.pWorkingTableData->IP=((UINT8*)ParserTempData.pWorkingTableData->pTableHead)+sizeof(ATOM_COMMON_ROM_COMMAND_TABLE_HEADER);
202						ParserTempData.pWorkingTableData->prevWorkingTableData=prevWorkingTableData;
203						prevWorkingTableData=ParserTempData.pWorkingTableData;
204						ParserTempData.Status = CD_SUCCESS;
205					} else ParserTempData.Status = CD_UNEXPECTED_BEHAVIOR;
206				} else ParserTempData.Status = CD_EXEC_TABLE_NOT_FOUND;
207			}
208			if (!CD_ERROR(ParserTempData.Status))
209			{
210				ParserTempData.Status = CD_SUCCESS;
211				while (!CD_ERROR_OR_COMPLETED(ParserTempData.Status))
212				{
213					if (IS_COMMAND_VALID(((COMMAND_HEADER*)ParserTempData.pWorkingTableData->IP)->Opcode))
214					{
215						ParserTempData.pCmd = (GENERIC_ATTRIBUTE_COMMAND*)ParserTempData.pWorkingTableData->IP;
216
217						if (IS_END_OF_TABLE(((COMMAND_HEADER*)ParserTempData.pWorkingTableData->IP)->Opcode))
218						{
219							ParserTempData.Status=CD_COMPLETED;
220							prevWorkingTableData=ParserTempData.pWorkingTableData->prevWorkingTableData;
221
222							FreeWorkSpace(pDeviceData, ParserTempData.pWorkingTableData);
223							ParserTempData.pWorkingTableData=prevWorkingTableData;
224							if (prevWorkingTableData!=NULL)
225							{
226								ATOM_TABLE_ATTRIBUTE lTableAttr;
227								lTableAttr = GetCommandTableAttribute(ParserTempData.pWorkingTableData->pTableHead);
228								ParserTempData.pDeviceData->pParameterSpace-=(lTableAttr.PS_SizeInBytes>>2);
229							}
230							// if there is a parent table where to return, then restore PS_pointer to the original state
231						}
232						else
233						{
234							IndexInMasterTable=ProcessCommandProperties((PARSER_TEMP_DATA STACK_BASED *)&ParserTempData);
235							(*CallTable[IndexInMasterTable].function)((PARSER_TEMP_DATA STACK_BASED *)&ParserTempData);
236#if (PARSER_TYPE!=DRIVER_TYPE_PARSER)
237							BIOS_STACK_MODIFIER();
238#endif
239						}
240					}
241					else
242					{
243						ParserTempData.Status=CD_INVALID_OPCODE;
244						break;
245					}
246
247				}	// while
248			}	// if
249			else
250				break;
251		} while (prevWorkingTableData!=NULL);
252		if (ParserTempData.Status == CD_COMPLETED) return CD_SUCCESS;
253		return ParserTempData.Status;
254	} else return CD_SUCCESS;
255}
256
257// EOF
258
259