xref: /rk3399_rockchip-uboot/drivers/bios_emulator/bios.c (revision ece92f85053b8df613edcf05b26a416cbc3d629c)
1*ece92f85SJason Jin /****************************************************************************
2*ece92f85SJason Jin *
3*ece92f85SJason Jin *                        BIOS emulator and interface
4*ece92f85SJason Jin *                      to Realmode X86 Emulator Library
5*ece92f85SJason Jin *
6*ece92f85SJason Jin *  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
7*ece92f85SJason Jin *  Jason Jin <Jason.jin@freescale.com>
8*ece92f85SJason Jin *
9*ece92f85SJason Jin *               Copyright (C) 1996-1999 SciTech Software, Inc.
10*ece92f85SJason Jin *
11*ece92f85SJason Jin *  ========================================================================
12*ece92f85SJason Jin *
13*ece92f85SJason Jin *  Permission to use, copy, modify, distribute, and sell this software and
14*ece92f85SJason Jin *  its documentation for any purpose is hereby granted without fee,
15*ece92f85SJason Jin *  provided that the above copyright notice appear in all copies and that
16*ece92f85SJason Jin *  both that copyright notice and this permission notice appear in
17*ece92f85SJason Jin *  supporting documentation, and that the name of the authors not be used
18*ece92f85SJason Jin *  in advertising or publicity pertaining to distribution of the software
19*ece92f85SJason Jin *  without specific, written prior permission.  The authors makes no
20*ece92f85SJason Jin *  representations about the suitability of this software for any purpose.
21*ece92f85SJason Jin *  It is provided "as is" without express or implied warranty.
22*ece92f85SJason Jin *
23*ece92f85SJason Jin *  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
24*ece92f85SJason Jin *  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
25*ece92f85SJason Jin *  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
26*ece92f85SJason Jin *  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
27*ece92f85SJason Jin *  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
28*ece92f85SJason Jin *  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
29*ece92f85SJason Jin *  PERFORMANCE OF THIS SOFTWARE.
30*ece92f85SJason Jin *
31*ece92f85SJason Jin *  ========================================================================
32*ece92f85SJason Jin *
33*ece92f85SJason Jin * Language:     ANSI C
34*ece92f85SJason Jin * Environment:  Any
35*ece92f85SJason Jin * Developer:    Kendall Bennett
36*ece92f85SJason Jin *
37*ece92f85SJason Jin * Description:  Module implementing the BIOS specific functions.
38*ece92f85SJason Jin *
39*ece92f85SJason Jin * 		Jason ported this file to u-boot to run the ATI video card
40*ece92f85SJason Jin * 		video BIOS.
41*ece92f85SJason Jin *
42*ece92f85SJason Jin ****************************************************************************/
43*ece92f85SJason Jin 
44*ece92f85SJason Jin #include "biosemui.h"
45*ece92f85SJason Jin 
46*ece92f85SJason Jin /*----------------------------- Implementation ----------------------------*/
47*ece92f85SJason Jin 
48*ece92f85SJason Jin /****************************************************************************
49*ece92f85SJason Jin PARAMETERS:
50*ece92f85SJason Jin intno   - Interrupt number being serviced
51*ece92f85SJason Jin 
52*ece92f85SJason Jin REMARKS:
53*ece92f85SJason Jin Handler for undefined interrupts.
54*ece92f85SJason Jin ****************************************************************************/
55*ece92f85SJason Jin static void X86API undefined_intr(int intno)
56*ece92f85SJason Jin {
57*ece92f85SJason Jin 	if (BE_rdw(intno * 4 + 2) == BIOS_SEG) {
58*ece92f85SJason Jin 		DB(printf("biosEmu: undefined interrupt %xh called!\n", intno);)
59*ece92f85SJason Jin 	} else
60*ece92f85SJason Jin 		X86EMU_prepareForInt(intno);
61*ece92f85SJason Jin }
62*ece92f85SJason Jin 
63*ece92f85SJason Jin /****************************************************************************
64*ece92f85SJason Jin PARAMETERS:
65*ece92f85SJason Jin intno   - Interrupt number being serviced
66*ece92f85SJason Jin 
67*ece92f85SJason Jin REMARKS:
68*ece92f85SJason Jin This function handles the default system BIOS Int 10h (the default is stored
69*ece92f85SJason Jin in the Int 42h vector by the system BIOS at bootup). We only need to handle
70*ece92f85SJason Jin a small number of special functions used by the BIOS during POST time.
71*ece92f85SJason Jin ****************************************************************************/
72*ece92f85SJason Jin static void X86API int42(int intno)
73*ece92f85SJason Jin {
74*ece92f85SJason Jin 	if (M.x86.R_AH == 0x12 && M.x86.R_BL == 0x32) {
75*ece92f85SJason Jin 		if (M.x86.R_AL == 0) {
76*ece92f85SJason Jin 			/* Enable CPU accesses to video memory */
77*ece92f85SJason Jin 			PM_outpb(0x3c2, PM_inpb(0x3cc) | (u8) 0x02);
78*ece92f85SJason Jin 			return;
79*ece92f85SJason Jin 		} else if (M.x86.R_AL == 1) {
80*ece92f85SJason Jin 			/* Disable CPU accesses to video memory */
81*ece92f85SJason Jin 			PM_outpb(0x3c2, PM_inpb(0x3cc) & (u8) ~ 0x02);
82*ece92f85SJason Jin 			return;
83*ece92f85SJason Jin 		}
84*ece92f85SJason Jin #ifdef  DEBUG
85*ece92f85SJason Jin 		else {
86*ece92f85SJason Jin 			printf("int42: unknown function AH=0x12, BL=0x32, AL=%#02x\n",
87*ece92f85SJason Jin 			     M.x86.R_AL);
88*ece92f85SJason Jin 		}
89*ece92f85SJason Jin #endif
90*ece92f85SJason Jin 	}
91*ece92f85SJason Jin #ifdef  DEBUG
92*ece92f85SJason Jin 	else {
93*ece92f85SJason Jin 		printf("int42: unknown function AH=%#02x, AL=%#02x, BL=%#02x\n",
94*ece92f85SJason Jin 		     M.x86.R_AH, M.x86.R_AL, M.x86.R_BL);
95*ece92f85SJason Jin 	}
96*ece92f85SJason Jin #endif
97*ece92f85SJason Jin }
98*ece92f85SJason Jin 
99*ece92f85SJason Jin /****************************************************************************
100*ece92f85SJason Jin PARAMETERS:
101*ece92f85SJason Jin intno   - Interrupt number being serviced
102*ece92f85SJason Jin 
103*ece92f85SJason Jin REMARKS:
104*ece92f85SJason Jin This function handles the default system BIOS Int 10h. If the POST code
105*ece92f85SJason Jin has not yet re-vectored the Int 10h BIOS interrupt vector, we handle this
106*ece92f85SJason Jin by simply calling the int42 interrupt handler above. Very early in the
107*ece92f85SJason Jin BIOS POST process, the vector gets replaced and we simply let the real
108*ece92f85SJason Jin mode interrupt handler process the interrupt.
109*ece92f85SJason Jin ****************************************************************************/
110*ece92f85SJason Jin static void X86API int10(int intno)
111*ece92f85SJason Jin {
112*ece92f85SJason Jin 	if (BE_rdw(intno * 4 + 2) == BIOS_SEG)
113*ece92f85SJason Jin 		int42(intno);
114*ece92f85SJason Jin 	else
115*ece92f85SJason Jin 		X86EMU_prepareForInt(intno);
116*ece92f85SJason Jin }
117*ece92f85SJason Jin 
118*ece92f85SJason Jin /* Result codes returned by the PCI BIOS */
119*ece92f85SJason Jin 
120*ece92f85SJason Jin #define SUCCESSFUL          0x00
121*ece92f85SJason Jin #define FUNC_NOT_SUPPORT    0x81
122*ece92f85SJason Jin #define BAD_VENDOR_ID       0x83
123*ece92f85SJason Jin #define DEVICE_NOT_FOUND    0x86
124*ece92f85SJason Jin #define BAD_REGISTER_NUMBER 0x87
125*ece92f85SJason Jin #define SET_FAILED          0x88
126*ece92f85SJason Jin #define BUFFER_TOO_SMALL    0x89
127*ece92f85SJason Jin 
128*ece92f85SJason Jin /****************************************************************************
129*ece92f85SJason Jin PARAMETERS:
130*ece92f85SJason Jin intno   - Interrupt number being serviced
131*ece92f85SJason Jin 
132*ece92f85SJason Jin REMARKS:
133*ece92f85SJason Jin This function handles the default Int 1Ah interrupt handler for the real
134*ece92f85SJason Jin mode code, which provides support for the PCI BIOS functions. Since we only
135*ece92f85SJason Jin want to allow the real mode BIOS code *only* see the PCI config space for
136*ece92f85SJason Jin its own device, we only return information for the specific PCI config
137*ece92f85SJason Jin space that we have passed in to the init function. This solves problems
138*ece92f85SJason Jin when using the BIOS to warm boot a secondary adapter when there is an
139*ece92f85SJason Jin identical adapter before it on the bus (some BIOS'es get confused in this
140*ece92f85SJason Jin case).
141*ece92f85SJason Jin ****************************************************************************/
142*ece92f85SJason Jin static void X86API int1A(int unused)
143*ece92f85SJason Jin {
144*ece92f85SJason Jin 	u16 pciSlot;
145*ece92f85SJason Jin 
146*ece92f85SJason Jin #ifdef __KERNEL__
147*ece92f85SJason Jin 	u8 interface, subclass, baseclass;
148*ece92f85SJason Jin 
149*ece92f85SJason Jin 	/* Initialise the PCI slot number */
150*ece92f85SJason Jin 	pciSlot = ((int)_BE_env.vgaInfo.bus << 8) |
151*ece92f85SJason Jin 	    ((int)_BE_env.vgaInfo.device << 3) | (int)_BE_env.vgaInfo.function;
152*ece92f85SJason Jin #else
153*ece92f85SJason Jin /* Fail if no PCI device information has been registered */
154*ece92f85SJason Jin 	if (!_BE_env.vgaInfo.pciInfo)
155*ece92f85SJason Jin 		return;
156*ece92f85SJason Jin 
157*ece92f85SJason Jin 	pciSlot = (u16) (_BE_env.vgaInfo.pciInfo->slot.i >> 8);
158*ece92f85SJason Jin #endif
159*ece92f85SJason Jin 	switch (M.x86.R_AX) {
160*ece92f85SJason Jin 	case 0xB101:		/* PCI bios present? */
161*ece92f85SJason Jin 		M.x86.R_AL = 0x00;	/* no config space/special cycle generation support */
162*ece92f85SJason Jin 		M.x86.R_EDX = 0x20494350;	/* " ICP" */
163*ece92f85SJason Jin 		M.x86.R_BX = 0x0210;	/* Version 2.10 */
164*ece92f85SJason Jin 		M.x86.R_CL = 0;	/* Max bus number in system */
165*ece92f85SJason Jin 		CLEAR_FLAG(F_CF);
166*ece92f85SJason Jin 		break;
167*ece92f85SJason Jin 	case 0xB102:		/* Find PCI device */
168*ece92f85SJason Jin 		M.x86.R_AH = DEVICE_NOT_FOUND;
169*ece92f85SJason Jin #ifdef __KERNEL__
170*ece92f85SJason Jin 		if (M.x86.R_DX == _BE_env.vgaInfo.VendorID &&
171*ece92f85SJason Jin 		    M.x86.R_CX == _BE_env.vgaInfo.DeviceID && M.x86.R_SI == 0) {
172*ece92f85SJason Jin #else
173*ece92f85SJason Jin 		if (M.x86.R_DX == _BE_env.vgaInfo.pciInfo->VendorID &&
174*ece92f85SJason Jin 		    M.x86.R_CX == _BE_env.vgaInfo.pciInfo->DeviceID &&
175*ece92f85SJason Jin 		    M.x86.R_SI == 0) {
176*ece92f85SJason Jin #endif
177*ece92f85SJason Jin 			M.x86.R_AH = SUCCESSFUL;
178*ece92f85SJason Jin 			M.x86.R_BX = pciSlot;
179*ece92f85SJason Jin 		}
180*ece92f85SJason Jin 		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
181*ece92f85SJason Jin 		break;
182*ece92f85SJason Jin 	case 0xB103:		/* Find PCI class code */
183*ece92f85SJason Jin 		M.x86.R_AH = DEVICE_NOT_FOUND;
184*ece92f85SJason Jin #ifdef __KERNEL__
185*ece92f85SJason Jin 		pci_read_config_byte(_BE_env.vgaInfo.pcidev, PCI_CLASS_PROG,
186*ece92f85SJason Jin 				     &interface);
187*ece92f85SJason Jin 		pci_read_config_byte(_BE_env.vgaInfo.pcidev, PCI_CLASS_DEVICE,
188*ece92f85SJason Jin 				     &subclass);
189*ece92f85SJason Jin 		pci_read_config_byte(_BE_env.vgaInfo.pcidev,
190*ece92f85SJason Jin 				     PCI_CLASS_DEVICE + 1, &baseclass);
191*ece92f85SJason Jin 		if (M.x86.R_CL == interface && M.x86.R_CH == subclass
192*ece92f85SJason Jin 		    && (u8) (M.x86.R_ECX >> 16) == baseclass) {
193*ece92f85SJason Jin #else
194*ece92f85SJason Jin 		if (M.x86.R_CL == _BE_env.vgaInfo.pciInfo->Interface &&
195*ece92f85SJason Jin 		    M.x86.R_CH == _BE_env.vgaInfo.pciInfo->SubClass &&
196*ece92f85SJason Jin 		    (u8) (M.x86.R_ECX >> 16) ==
197*ece92f85SJason Jin 		    _BE_env.vgaInfo.pciInfo->BaseClass) {
198*ece92f85SJason Jin #endif
199*ece92f85SJason Jin 			M.x86.R_AH = SUCCESSFUL;
200*ece92f85SJason Jin 			M.x86.R_BX = pciSlot;
201*ece92f85SJason Jin 		}
202*ece92f85SJason Jin 		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
203*ece92f85SJason Jin 		break;
204*ece92f85SJason Jin 	case 0xB108:		/* Read configuration byte */
205*ece92f85SJason Jin 		M.x86.R_AH = BAD_REGISTER_NUMBER;
206*ece92f85SJason Jin 		if (M.x86.R_BX == pciSlot) {
207*ece92f85SJason Jin 			M.x86.R_AH = SUCCESSFUL;
208*ece92f85SJason Jin #ifdef __KERNEL__
209*ece92f85SJason Jin 			pci_read_config_byte(_BE_env.vgaInfo.pcidev, M.x86.R_DI,
210*ece92f85SJason Jin 					     &M.x86.R_CL);
211*ece92f85SJason Jin #else
212*ece92f85SJason Jin 			M.x86.R_CL =
213*ece92f85SJason Jin 			    (u8) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_BYTE,
214*ece92f85SJason Jin 					       _BE_env.vgaInfo.pciInfo);
215*ece92f85SJason Jin #endif
216*ece92f85SJason Jin 		}
217*ece92f85SJason Jin 		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
218*ece92f85SJason Jin 		break;
219*ece92f85SJason Jin 	case 0xB109:		/* Read configuration word */
220*ece92f85SJason Jin 		M.x86.R_AH = BAD_REGISTER_NUMBER;
221*ece92f85SJason Jin 		if (M.x86.R_BX == pciSlot) {
222*ece92f85SJason Jin 			M.x86.R_AH = SUCCESSFUL;
223*ece92f85SJason Jin #ifdef __KERNEL__
224*ece92f85SJason Jin 			pci_read_config_word(_BE_env.vgaInfo.pcidev, M.x86.R_DI,
225*ece92f85SJason Jin 					     &M.x86.R_CX);
226*ece92f85SJason Jin #else
227*ece92f85SJason Jin 			M.x86.R_CX =
228*ece92f85SJason Jin 			    (u16) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_WORD,
229*ece92f85SJason Jin 						_BE_env.vgaInfo.pciInfo);
230*ece92f85SJason Jin #endif
231*ece92f85SJason Jin 		}
232*ece92f85SJason Jin 		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
233*ece92f85SJason Jin 		break;
234*ece92f85SJason Jin 	case 0xB10A:		/* Read configuration dword */
235*ece92f85SJason Jin 		M.x86.R_AH = BAD_REGISTER_NUMBER;
236*ece92f85SJason Jin 		if (M.x86.R_BX == pciSlot) {
237*ece92f85SJason Jin 			M.x86.R_AH = SUCCESSFUL;
238*ece92f85SJason Jin #ifdef __KERNEL__
239*ece92f85SJason Jin 			pci_read_config_dword(_BE_env.vgaInfo.pcidev,
240*ece92f85SJason Jin 					      M.x86.R_DI, &M.x86.R_ECX);
241*ece92f85SJason Jin #else
242*ece92f85SJason Jin 			M.x86.R_ECX =
243*ece92f85SJason Jin 			    (u32) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_DWORD,
244*ece92f85SJason Jin 						_BE_env.vgaInfo.pciInfo);
245*ece92f85SJason Jin #endif
246*ece92f85SJason Jin 		}
247*ece92f85SJason Jin 		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
248*ece92f85SJason Jin 		break;
249*ece92f85SJason Jin 	case 0xB10B:		/* Write configuration byte */
250*ece92f85SJason Jin 		M.x86.R_AH = BAD_REGISTER_NUMBER;
251*ece92f85SJason Jin 		if (M.x86.R_BX == pciSlot) {
252*ece92f85SJason Jin 			M.x86.R_AH = SUCCESSFUL;
253*ece92f85SJason Jin #ifdef __KERNEL__
254*ece92f85SJason Jin 			pci_write_config_byte(_BE_env.vgaInfo.pcidev,
255*ece92f85SJason Jin 					      M.x86.R_DI, M.x86.R_CL);
256*ece92f85SJason Jin #else
257*ece92f85SJason Jin 			PCI_accessReg(M.x86.R_DI, M.x86.R_CL, PCI_WRITE_BYTE,
258*ece92f85SJason Jin 				      _BE_env.vgaInfo.pciInfo);
259*ece92f85SJason Jin #endif
260*ece92f85SJason Jin 		}
261*ece92f85SJason Jin 		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
262*ece92f85SJason Jin 		break;
263*ece92f85SJason Jin 	case 0xB10C:		/* Write configuration word */
264*ece92f85SJason Jin 		M.x86.R_AH = BAD_REGISTER_NUMBER;
265*ece92f85SJason Jin 		if (M.x86.R_BX == pciSlot) {
266*ece92f85SJason Jin 			M.x86.R_AH = SUCCESSFUL;
267*ece92f85SJason Jin #ifdef __KERNEL__
268*ece92f85SJason Jin 			pci_write_config_word(_BE_env.vgaInfo.pcidev,
269*ece92f85SJason Jin 					      M.x86.R_DI, M.x86.R_CX);
270*ece92f85SJason Jin #else
271*ece92f85SJason Jin 			PCI_accessReg(M.x86.R_DI, M.x86.R_CX, PCI_WRITE_WORD,
272*ece92f85SJason Jin 				      _BE_env.vgaInfo.pciInfo);
273*ece92f85SJason Jin #endif
274*ece92f85SJason Jin 		}
275*ece92f85SJason Jin 		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
276*ece92f85SJason Jin 		break;
277*ece92f85SJason Jin 	case 0xB10D:		/* Write configuration dword */
278*ece92f85SJason Jin 		M.x86.R_AH = BAD_REGISTER_NUMBER;
279*ece92f85SJason Jin 		if (M.x86.R_BX == pciSlot) {
280*ece92f85SJason Jin 			M.x86.R_AH = SUCCESSFUL;
281*ece92f85SJason Jin #ifdef __KERNEL__
282*ece92f85SJason Jin 			pci_write_config_dword(_BE_env.vgaInfo.pcidev,
283*ece92f85SJason Jin 					       M.x86.R_DI, M.x86.R_ECX);
284*ece92f85SJason Jin #else
285*ece92f85SJason Jin 			PCI_accessReg(M.x86.R_DI, M.x86.R_ECX, PCI_WRITE_DWORD,
286*ece92f85SJason Jin 				      _BE_env.vgaInfo.pciInfo);
287*ece92f85SJason Jin #endif
288*ece92f85SJason Jin 		}
289*ece92f85SJason Jin 		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
290*ece92f85SJason Jin 		break;
291*ece92f85SJason Jin 	default:
292*ece92f85SJason Jin 		printf("biosEmu/bios.int1a: unknown function AX=%#04x\n",
293*ece92f85SJason Jin 		       M.x86.R_AX);
294*ece92f85SJason Jin 	}
295*ece92f85SJason Jin }
296*ece92f85SJason Jin 
297*ece92f85SJason Jin /****************************************************************************
298*ece92f85SJason Jin REMARKS:
299*ece92f85SJason Jin This function initialises the BIOS emulation functions for the specific
300*ece92f85SJason Jin PCI display device. We insulate the real mode BIOS from any other devices
301*ece92f85SJason Jin on the bus, so that it will work correctly thinking that it is the only
302*ece92f85SJason Jin device present on the bus (ie: avoiding any adapters present in from of
303*ece92f85SJason Jin the device we are trying to control).
304*ece92f85SJason Jin ****************************************************************************/
305*ece92f85SJason Jin #define BE_constLE_32(v)    ((((((v)&0xff00)>>8)|(((v)&0xff)<<8))<<16)|(((((v)&0xff000000)>>8)|(((v)&0x00ff0000)<<8))>>16))
306*ece92f85SJason Jin 
307*ece92f85SJason Jin void _BE_bios_init(u32 * intrTab)
308*ece92f85SJason Jin {
309*ece92f85SJason Jin 	int i;
310*ece92f85SJason Jin 	X86EMU_intrFuncs bios_intr_tab[256];
311*ece92f85SJason Jin 
312*ece92f85SJason Jin 	for (i = 0; i < 256; ++i) {
313*ece92f85SJason Jin 		intrTab[i] = BE_constLE_32(BIOS_SEG << 16);
314*ece92f85SJason Jin 		bios_intr_tab[i] = undefined_intr;
315*ece92f85SJason Jin 	}
316*ece92f85SJason Jin 	bios_intr_tab[0x10] = int10;
317*ece92f85SJason Jin 	bios_intr_tab[0x1A] = int1A;
318*ece92f85SJason Jin 	bios_intr_tab[0x42] = int42;
319*ece92f85SJason Jin 	bios_intr_tab[0x6D] = int10;
320*ece92f85SJason Jin 	X86EMU_setupIntrFuncs(bios_intr_tab);
321*ece92f85SJason Jin }
322