xref: /OK3568_Linux_fs/u-boot/drivers/bios_emulator/atibios.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /****************************************************************************
2*4882a593Smuzhiyun *
3*4882a593Smuzhiyun *		     Video BOOT Graphics Card POST Module
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun *  ========================================================================
6*4882a593Smuzhiyun *   Copyright (C) 2007 Freescale Semiconductor, Inc.
7*4882a593Smuzhiyun *   Jason Jin <Jason.jin@freescale.com>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun *   Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun *   This file may be distributed and/or modified under the terms of the
12*4882a593Smuzhiyun *   GNU General Public License version 2.0 as published by the Free
13*4882a593Smuzhiyun *   Software Foundation and appearing in the file LICENSE.GPL included
14*4882a593Smuzhiyun *   in the packaging of this file.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun *   Licensees holding a valid Commercial License for this product from
17*4882a593Smuzhiyun *   SciTech Software, Inc. may use this file in accordance with the
18*4882a593Smuzhiyun *   Commercial License Agreement provided with the Software.
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun *   This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
21*4882a593Smuzhiyun *   THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*4882a593Smuzhiyun *   PURPOSE.
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun *   See http://www.scitechsoft.com/license/ for information about
25*4882a593Smuzhiyun *   the licensing options available and how to purchase a Commercial
26*4882a593Smuzhiyun *   License Agreement.
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun *   Contact license@scitechsoft.com if any conditions of this licensing
29*4882a593Smuzhiyun *   are not clear to you, or you have questions about licensing options.
30*4882a593Smuzhiyun *
31*4882a593Smuzhiyun *  ========================================================================
32*4882a593Smuzhiyun *
33*4882a593Smuzhiyun * Language:	ANSI C
34*4882a593Smuzhiyun * Environment:	Linux Kernel
35*4882a593Smuzhiyun * Developer:	Kendall Bennett
36*4882a593Smuzhiyun *
37*4882a593Smuzhiyun * Description:	Module to implement booting PCI/AGP controllers on the
38*4882a593Smuzhiyun *		bus. We use the x86 real mode emulator to run the BIOS on
39*4882a593Smuzhiyun *		graphics controllers to bring the cards up.
40*4882a593Smuzhiyun *
41*4882a593Smuzhiyun *		Note that at present this module does *not* support
42*4882a593Smuzhiyun *		multiple controllers.
43*4882a593Smuzhiyun *
44*4882a593Smuzhiyun *		The orignal name of this file is warmboot.c.
45*4882a593Smuzhiyun *		Jason ported this file to u-boot to run the ATI video card
46*4882a593Smuzhiyun *		BIOS in u-boot.
47*4882a593Smuzhiyun ****************************************************************************/
48*4882a593Smuzhiyun #include <common.h>
49*4882a593Smuzhiyun #include <bios_emul.h>
50*4882a593Smuzhiyun #include <errno.h>
51*4882a593Smuzhiyun #include <malloc.h>
52*4882a593Smuzhiyun #include <vbe.h>
53*4882a593Smuzhiyun #include "biosemui.h"
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun /* Length of the BIOS image */
56*4882a593Smuzhiyun #define MAX_BIOSLEN	    (128 * 1024L)
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /* Place to save PCI BAR's that we change and later restore */
59*4882a593Smuzhiyun static u32 saveROMBaseAddress;
60*4882a593Smuzhiyun static u32 saveBaseAddress10;
61*4882a593Smuzhiyun static u32 saveBaseAddress14;
62*4882a593Smuzhiyun static u32 saveBaseAddress18;
63*4882a593Smuzhiyun static u32 saveBaseAddress20;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /* Addres im memory of VBE region */
66*4882a593Smuzhiyun const int vbe_offset = 0x2000;
67*4882a593Smuzhiyun 
bios_ptr(const void * buf,BE_VGAInfo * vga_info,u32 x86_dword_ptr)68*4882a593Smuzhiyun static const void *bios_ptr(const void *buf, BE_VGAInfo *vga_info,
69*4882a593Smuzhiyun 			    u32 x86_dword_ptr)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	u32 seg_ofs, flat;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	seg_ofs = le32_to_cpu(x86_dword_ptr);
74*4882a593Smuzhiyun 	flat = ((seg_ofs & 0xffff0000) >> 12) | (seg_ofs & 0xffff);
75*4882a593Smuzhiyun 	if (flat >= 0xc0000)
76*4882a593Smuzhiyun 		return vga_info->BIOSImage + flat - 0xc0000;
77*4882a593Smuzhiyun 	else
78*4882a593Smuzhiyun 		return buf + (flat - vbe_offset);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
atibios_debug_mode(BE_VGAInfo * vga_info,RMREGS * regs,int vesa_mode,struct vbe_mode_info * mode_info)81*4882a593Smuzhiyun static int atibios_debug_mode(BE_VGAInfo *vga_info, RMREGS *regs,
82*4882a593Smuzhiyun 			      int vesa_mode, struct vbe_mode_info *mode_info)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	void *buffer = (void *)(M.mem_base + vbe_offset);
85*4882a593Smuzhiyun 	u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
86*4882a593Smuzhiyun 	u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
87*4882a593Smuzhiyun 	struct vesa_mode_info *vm;
88*4882a593Smuzhiyun 	struct vbe_info *info;
89*4882a593Smuzhiyun 	const u16 *modes_bios, *ptr;
90*4882a593Smuzhiyun 	u16 *modes;
91*4882a593Smuzhiyun 	int size;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	debug("VBE: Getting information\n");
94*4882a593Smuzhiyun 	regs->e.eax = VESA_GET_INFO;
95*4882a593Smuzhiyun 	regs->e.esi = buffer_seg;
96*4882a593Smuzhiyun 	regs->e.edi = buffer_adr;
97*4882a593Smuzhiyun 	info = buffer;
98*4882a593Smuzhiyun 	memset(info, '\0', sizeof(*info));
99*4882a593Smuzhiyun 	strcpy(info->signature, "VBE2");
100*4882a593Smuzhiyun 	BE_int86(0x10, regs, regs);
101*4882a593Smuzhiyun 	if (regs->e.eax != 0x4f) {
102*4882a593Smuzhiyun 		debug("VESA_GET_INFO: error %x\n", regs->e.eax);
103*4882a593Smuzhiyun 		return -ENOSYS;
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun 	debug("version %x\n", le16_to_cpu(info->version));
106*4882a593Smuzhiyun 	debug("oem '%s'\n", (char *)bios_ptr(buffer, vga_info,
107*4882a593Smuzhiyun 					     info->oem_string_ptr));
108*4882a593Smuzhiyun 	debug("vendor '%s'\n", (char *)bios_ptr(buffer, vga_info,
109*4882a593Smuzhiyun 						info->vendor_name_ptr));
110*4882a593Smuzhiyun 	debug("product '%s'\n", (char *)bios_ptr(buffer, vga_info,
111*4882a593Smuzhiyun 						 info->product_name_ptr));
112*4882a593Smuzhiyun 	debug("rev '%s'\n", (char *)bios_ptr(buffer, vga_info,
113*4882a593Smuzhiyun 					     info->product_rev_ptr));
114*4882a593Smuzhiyun 	modes_bios = bios_ptr(buffer, vga_info, info->modes_ptr);
115*4882a593Smuzhiyun 	debug("Modes: ");
116*4882a593Smuzhiyun 	for (ptr = modes_bios; *ptr != 0xffff; ptr++)
117*4882a593Smuzhiyun 		debug("%x ", le16_to_cpu(*ptr));
118*4882a593Smuzhiyun 	debug("\nmemory %dMB\n", le16_to_cpu(info->total_memory) >> 4);
119*4882a593Smuzhiyun 	size = (ptr - modes_bios) * sizeof(u16) + 2;
120*4882a593Smuzhiyun 	modes = malloc(size);
121*4882a593Smuzhiyun 	if (!modes)
122*4882a593Smuzhiyun 		return -ENOMEM;
123*4882a593Smuzhiyun 	memcpy(modes, modes_bios, size);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	regs->e.eax = VESA_GET_CUR_MODE;
126*4882a593Smuzhiyun 	BE_int86(0x10, regs, regs);
127*4882a593Smuzhiyun 	if (regs->e.eax != 0x4f) {
128*4882a593Smuzhiyun 		debug("VESA_GET_CUR_MODE: error %x\n", regs->e.eax);
129*4882a593Smuzhiyun 		return -ENOSYS;
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 	debug("Current mode %x\n", regs->e.ebx);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	for (ptr = modes; *ptr != 0xffff; ptr++) {
134*4882a593Smuzhiyun 		int mode = le16_to_cpu(*ptr);
135*4882a593Smuzhiyun 		bool linear_ok;
136*4882a593Smuzhiyun 		int attr;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 		break;
139*4882a593Smuzhiyun 		debug("Mode %x: ", mode);
140*4882a593Smuzhiyun 		memset(buffer, '\0', sizeof(struct vbe_mode_info));
141*4882a593Smuzhiyun 		regs->e.eax = VESA_GET_MODE_INFO;
142*4882a593Smuzhiyun 		regs->e.ebx = 0;
143*4882a593Smuzhiyun 		regs->e.ecx = mode;
144*4882a593Smuzhiyun 		regs->e.edx = 0;
145*4882a593Smuzhiyun 		regs->e.esi = buffer_seg;
146*4882a593Smuzhiyun 		regs->e.edi = buffer_adr;
147*4882a593Smuzhiyun 		BE_int86(0x10, regs, regs);
148*4882a593Smuzhiyun 		if (regs->e.eax != 0x4f) {
149*4882a593Smuzhiyun 			debug("VESA_GET_MODE_INFO: error %x\n", regs->e.eax);
150*4882a593Smuzhiyun 			continue;
151*4882a593Smuzhiyun 		}
152*4882a593Smuzhiyun 		memcpy(mode_info->mode_info_block, buffer,
153*4882a593Smuzhiyun 		       sizeof(struct vesa_mode_info));
154*4882a593Smuzhiyun 		mode_info->valid = true;
155*4882a593Smuzhiyun 		vm = &mode_info->vesa;
156*4882a593Smuzhiyun 		attr = le16_to_cpu(vm->mode_attributes);
157*4882a593Smuzhiyun 		linear_ok = attr & 0x80;
158*4882a593Smuzhiyun 		debug("res %d x %d, %d bpp, mm %d, (Linear %s, attr %02x)\n",
159*4882a593Smuzhiyun 		      le16_to_cpu(vm->x_resolution),
160*4882a593Smuzhiyun 		      le16_to_cpu(vm->y_resolution),
161*4882a593Smuzhiyun 		      vm->bits_per_pixel, vm->memory_model,
162*4882a593Smuzhiyun 		      linear_ok ? "OK" : "not available",
163*4882a593Smuzhiyun 		      attr);
164*4882a593Smuzhiyun 		debug("\tRGB pos=%d,%d,%d, size=%d,%d,%d\n",
165*4882a593Smuzhiyun 		      vm->red_mask_pos, vm->green_mask_pos, vm->blue_mask_pos,
166*4882a593Smuzhiyun 		      vm->red_mask_size, vm->green_mask_size,
167*4882a593Smuzhiyun 		      vm->blue_mask_size);
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	return 0;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun 
atibios_set_vesa_mode(RMREGS * regs,int vesa_mode,struct vbe_mode_info * mode_info)173*4882a593Smuzhiyun static int atibios_set_vesa_mode(RMREGS *regs, int vesa_mode,
174*4882a593Smuzhiyun 				 struct vbe_mode_info *mode_info)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	void *buffer = (void *)(M.mem_base + vbe_offset);
177*4882a593Smuzhiyun 	u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
178*4882a593Smuzhiyun 	u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
179*4882a593Smuzhiyun 	struct vesa_mode_info *vm;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	debug("VBE: Setting VESA mode %#04x\n", vesa_mode);
182*4882a593Smuzhiyun 	regs->e.eax = VESA_SET_MODE;
183*4882a593Smuzhiyun 	regs->e.ebx = vesa_mode;
184*4882a593Smuzhiyun 	/* request linear framebuffer mode and don't clear display */
185*4882a593Smuzhiyun 	regs->e.ebx |= (1 << 14) | (1 << 15);
186*4882a593Smuzhiyun 	BE_int86(0x10, regs, regs);
187*4882a593Smuzhiyun 	if (regs->e.eax != 0x4f) {
188*4882a593Smuzhiyun 		debug("VESA_SET_MODE: error %x\n", regs->e.eax);
189*4882a593Smuzhiyun 		return -ENOSYS;
190*4882a593Smuzhiyun 	}
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	memset(buffer, '\0', sizeof(struct vbe_mode_info));
193*4882a593Smuzhiyun 	debug("VBE: Geting info for VESA mode %#04x\n", vesa_mode);
194*4882a593Smuzhiyun 	regs->e.eax = VESA_GET_MODE_INFO;
195*4882a593Smuzhiyun 	regs->e.ecx = vesa_mode;
196*4882a593Smuzhiyun 	regs->e.esi = buffer_seg;
197*4882a593Smuzhiyun 	regs->e.edi = buffer_adr;
198*4882a593Smuzhiyun 	BE_int86(0x10, regs, regs);
199*4882a593Smuzhiyun 	if (regs->e.eax != 0x4f) {
200*4882a593Smuzhiyun 		debug("VESA_GET_MODE_INFO: error %x\n", regs->e.eax);
201*4882a593Smuzhiyun 		return -ENOSYS;
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	memcpy(mode_info->mode_info_block, buffer,
205*4882a593Smuzhiyun 		sizeof(struct vesa_mode_info));
206*4882a593Smuzhiyun 	mode_info->valid = true;
207*4882a593Smuzhiyun 	mode_info->video_mode = vesa_mode;
208*4882a593Smuzhiyun 	vm = &mode_info->vesa;
209*4882a593Smuzhiyun 	vm->x_resolution = le16_to_cpu(vm->x_resolution);
210*4882a593Smuzhiyun 	vm->y_resolution = le16_to_cpu(vm->y_resolution);
211*4882a593Smuzhiyun 	vm->bytes_per_scanline = le16_to_cpu(vm->bytes_per_scanline);
212*4882a593Smuzhiyun 	vm->phys_base_ptr = le32_to_cpu(vm->phys_base_ptr);
213*4882a593Smuzhiyun 	vm->mode_attributes = le16_to_cpu(vm->mode_attributes);
214*4882a593Smuzhiyun 	debug("VBE: Init complete\n");
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	return 0;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun /****************************************************************************
220*4882a593Smuzhiyun PARAMETERS:
221*4882a593Smuzhiyun pcidev	- PCI device info for the video card on the bus to boot
222*4882a593Smuzhiyun vga_info - BIOS emulator VGA info structure
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun REMARKS:
225*4882a593Smuzhiyun This function executes the BIOS POST code on the controller. We assume that
226*4882a593Smuzhiyun at this stage the controller has its I/O and memory space enabled and
227*4882a593Smuzhiyun that all other controllers are in a disabled state.
228*4882a593Smuzhiyun ****************************************************************************/
229*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
PCI_doBIOSPOST(struct udevice * pcidev,BE_VGAInfo * vga_info,int vesa_mode,struct vbe_mode_info * mode_info)230*4882a593Smuzhiyun static void PCI_doBIOSPOST(struct udevice *pcidev, BE_VGAInfo *vga_info,
231*4882a593Smuzhiyun 			   int vesa_mode, struct vbe_mode_info *mode_info)
232*4882a593Smuzhiyun #else
233*4882a593Smuzhiyun static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo *vga_info,
234*4882a593Smuzhiyun 			   int vesa_mode, struct vbe_mode_info *mode_info)
235*4882a593Smuzhiyun #endif
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	RMREGS regs;
238*4882a593Smuzhiyun 	RMSREGS sregs;
239*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
240*4882a593Smuzhiyun 	pci_dev_t bdf;
241*4882a593Smuzhiyun #endif
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	/* Determine the value to store in AX for BIOS POST. Per the PCI specs,
244*4882a593Smuzhiyun 	 AH must contain the bus and AL must contain the devfn, encoded as
245*4882a593Smuzhiyun 	 (dev << 3) | fn
246*4882a593Smuzhiyun 	 */
247*4882a593Smuzhiyun 	memset(&regs, 0, sizeof(regs));
248*4882a593Smuzhiyun 	memset(&sregs, 0, sizeof(sregs));
249*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
250*4882a593Smuzhiyun 	bdf = dm_pci_get_bdf(pcidev);
251*4882a593Smuzhiyun 	regs.x.ax = (int)PCI_BUS(bdf) << 8 |
252*4882a593Smuzhiyun 			(int)PCI_DEV(bdf) << 3 | (int)PCI_FUNC(bdf);
253*4882a593Smuzhiyun #else
254*4882a593Smuzhiyun 	regs.x.ax = ((int)PCI_BUS(pcidev) << 8) |
255*4882a593Smuzhiyun 	    ((int)PCI_DEV(pcidev) << 3) | (int)PCI_FUNC(pcidev);
256*4882a593Smuzhiyun #endif
257*4882a593Smuzhiyun 	/*Setup the X86 emulator for the VGA BIOS*/
258*4882a593Smuzhiyun 	BE_setVGA(vga_info);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	/*Execute the BIOS POST code*/
261*4882a593Smuzhiyun 	BE_callRealMode(0xC000, 0x0003, &regs, &sregs);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	/*Cleanup and exit*/
264*4882a593Smuzhiyun 	BE_getVGA(vga_info);
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	/* Useful for debugging */
267*4882a593Smuzhiyun 	if (0)
268*4882a593Smuzhiyun 		atibios_debug_mode(vga_info, &regs, vesa_mode, mode_info);
269*4882a593Smuzhiyun 	if (vesa_mode != -1)
270*4882a593Smuzhiyun 		atibios_set_vesa_mode(&regs, vesa_mode, mode_info);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun /****************************************************************************
274*4882a593Smuzhiyun PARAMETERS:
275*4882a593Smuzhiyun pcidev	- PCI device info for the video card on the bus
276*4882a593Smuzhiyun bar	- Place to return the base address register offset to use
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun RETURNS:
279*4882a593Smuzhiyun The address to use to map the secondary BIOS (AGP devices)
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun REMARKS:
282*4882a593Smuzhiyun Searches all the PCI base address registers for the device looking for a
283*4882a593Smuzhiyun memory mapping that is large enough to hold our ROM BIOS. We usually end up
284*4882a593Smuzhiyun finding the framebuffer mapping (usually BAR 0x10), and we use this mapping
285*4882a593Smuzhiyun to map the BIOS for the device into. We use a mapping that is already
286*4882a593Smuzhiyun assigned to the device to ensure the memory range will be passed through
287*4882a593Smuzhiyun by any PCI->PCI or AGP->PCI bridge that may be present.
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun NOTE: Usually this function is only used for AGP devices, but it may be
290*4882a593Smuzhiyun       used for PCI devices that have already been POST'ed and the BIOS
291*4882a593Smuzhiyun       ROM base address has been zero'ed out.
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun NOTE: This function leaves the original memory aperture disabled by leaving
294*4882a593Smuzhiyun       it programmed to all 1's. It must be restored to the correct value
295*4882a593Smuzhiyun       later.
296*4882a593Smuzhiyun ****************************************************************************/
297*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
PCI_findBIOSAddr(struct udevice * pcidev,int * bar)298*4882a593Smuzhiyun static u32 PCI_findBIOSAddr(struct udevice *pcidev, int *bar)
299*4882a593Smuzhiyun #else
300*4882a593Smuzhiyun static u32 PCI_findBIOSAddr(pci_dev_t pcidev, int *bar)
301*4882a593Smuzhiyun #endif
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	u32 base, size;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	for (*bar = 0x10; *bar <= 0x14; (*bar) += 4) {
306*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
307*4882a593Smuzhiyun 		dm_pci_read_config32(pcidev, *bar, &base);
308*4882a593Smuzhiyun #else
309*4882a593Smuzhiyun 		pci_read_config_dword(pcidev, *bar, &base);
310*4882a593Smuzhiyun #endif
311*4882a593Smuzhiyun 		if (!(base & 0x1)) {
312*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
313*4882a593Smuzhiyun 			dm_pci_write_config32(pcidev, *bar, 0xFFFFFFFF);
314*4882a593Smuzhiyun 			dm_pci_read_config32(pcidev, *bar, &size);
315*4882a593Smuzhiyun #else
316*4882a593Smuzhiyun 			pci_write_config_dword(pcidev, *bar, 0xFFFFFFFF);
317*4882a593Smuzhiyun 			pci_read_config_dword(pcidev, *bar, &size);
318*4882a593Smuzhiyun #endif
319*4882a593Smuzhiyun 			size = ~(size & ~0xFF) + 1;
320*4882a593Smuzhiyun 			if (size >= MAX_BIOSLEN)
321*4882a593Smuzhiyun 				return base & ~0xFF;
322*4882a593Smuzhiyun 		}
323*4882a593Smuzhiyun 	}
324*4882a593Smuzhiyun 	return 0;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun /****************************************************************************
328*4882a593Smuzhiyun REMARKS:
329*4882a593Smuzhiyun Some non-x86 Linux kernels map PCI relocateable I/O to values that
330*4882a593Smuzhiyun are above 64K, which will not work with the BIOS image that requires
331*4882a593Smuzhiyun the offset for the I/O ports to be a maximum of 16-bits. Ideally
332*4882a593Smuzhiyun someone should fix the kernel to map the I/O ports for VGA compatible
333*4882a593Smuzhiyun devices to a different location (or just all I/O ports since it is
334*4882a593Smuzhiyun unlikely you can have enough devices in the machine to use up all
335*4882a593Smuzhiyun 64K of the I/O space - a total of more than 256 cards would be
336*4882a593Smuzhiyun necessary).
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun Anyway to fix this we change all I/O mapped base registers and
339*4882a593Smuzhiyun chop off the top bits.
340*4882a593Smuzhiyun ****************************************************************************/
341*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
PCI_fixupIObase(struct udevice * pcidev,int reg,u32 * base)342*4882a593Smuzhiyun static void PCI_fixupIObase(struct udevice *pcidev, int reg, u32 *base)
343*4882a593Smuzhiyun #else
344*4882a593Smuzhiyun static void PCI_fixupIObase(pci_dev_t pcidev, int reg, u32 * base)
345*4882a593Smuzhiyun #endif
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun 	if ((*base & 0x1) && (*base > 0xFFFE)) {
348*4882a593Smuzhiyun 		*base &= 0xFFFF;
349*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
350*4882a593Smuzhiyun 		dm_pci_write_config32(pcidev, reg, *base);
351*4882a593Smuzhiyun #else
352*4882a593Smuzhiyun 		pci_write_config_dword(pcidev, reg, *base);
353*4882a593Smuzhiyun #endif
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	}
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun /****************************************************************************
359*4882a593Smuzhiyun PARAMETERS:
360*4882a593Smuzhiyun pcidev	- PCI device info for the video card on the bus
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun RETURNS:
363*4882a593Smuzhiyun Pointers to the mapped BIOS image
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun REMARKS:
366*4882a593Smuzhiyun Maps a pointer to the BIOS image on the graphics card on the PCI bus.
367*4882a593Smuzhiyun ****************************************************************************/
368*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
PCI_mapBIOSImage(struct udevice * pcidev)369*4882a593Smuzhiyun void *PCI_mapBIOSImage(struct udevice *pcidev)
370*4882a593Smuzhiyun #else
371*4882a593Smuzhiyun void *PCI_mapBIOSImage(pci_dev_t pcidev)
372*4882a593Smuzhiyun #endif
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	u32 BIOSImageBus;
375*4882a593Smuzhiyun 	int BIOSImageBAR;
376*4882a593Smuzhiyun 	u8 *BIOSImage;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	/*Save PCI BAR registers that might get changed*/
379*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
380*4882a593Smuzhiyun 	dm_pci_read_config32(pcidev, PCI_ROM_ADDRESS, &saveROMBaseAddress);
381*4882a593Smuzhiyun 	dm_pci_read_config32(pcidev, PCI_BASE_ADDRESS_0, &saveBaseAddress10);
382*4882a593Smuzhiyun 	dm_pci_read_config32(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14);
383*4882a593Smuzhiyun 	dm_pci_read_config32(pcidev, PCI_BASE_ADDRESS_2, &saveBaseAddress18);
384*4882a593Smuzhiyun 	dm_pci_read_config32(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20);
385*4882a593Smuzhiyun #else
386*4882a593Smuzhiyun 	pci_read_config_dword(pcidev, PCI_ROM_ADDRESS, &saveROMBaseAddress);
387*4882a593Smuzhiyun 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &saveBaseAddress10);
388*4882a593Smuzhiyun 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14);
389*4882a593Smuzhiyun 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_2, &saveBaseAddress18);
390*4882a593Smuzhiyun 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20);
391*4882a593Smuzhiyun #endif
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	/*Fix up I/O base registers to less than 64K */
394*4882a593Smuzhiyun 	if(saveBaseAddress14 != 0)
395*4882a593Smuzhiyun 		PCI_fixupIObase(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14);
396*4882a593Smuzhiyun 	else
397*4882a593Smuzhiyun 		PCI_fixupIObase(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* Some cards have problems that stop us from being able to read the
400*4882a593Smuzhiyun 	 BIOS image from the ROM BAR. To fix this we have to do some chipset
401*4882a593Smuzhiyun 	 specific programming for different cards to solve this problem.
402*4882a593Smuzhiyun 	*/
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	BIOSImageBus = PCI_findBIOSAddr(pcidev, &BIOSImageBAR);
405*4882a593Smuzhiyun 	if (BIOSImageBus == 0) {
406*4882a593Smuzhiyun 		printf("Find bios addr error\n");
407*4882a593Smuzhiyun 		return NULL;
408*4882a593Smuzhiyun 	}
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
411*4882a593Smuzhiyun 	BIOSImage = dm_pci_bus_to_virt(pcidev, BIOSImageBus,
412*4882a593Smuzhiyun 				       PCI_REGION_MEM, 0, MAP_NOCACHE);
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	/*Change the PCI BAR registers to map it onto the bus.*/
415*4882a593Smuzhiyun 	dm_pci_write_config32(pcidev, BIOSImageBAR, 0);
416*4882a593Smuzhiyun 	dm_pci_write_config32(pcidev, PCI_ROM_ADDRESS, BIOSImageBus | 0x1);
417*4882a593Smuzhiyun #else
418*4882a593Smuzhiyun 	BIOSImage = pci_bus_to_virt(pcidev, BIOSImageBus,
419*4882a593Smuzhiyun 				    PCI_REGION_MEM, 0, MAP_NOCACHE);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	/*Change the PCI BAR registers to map it onto the bus.*/
422*4882a593Smuzhiyun 	pci_write_config_dword(pcidev, BIOSImageBAR, 0);
423*4882a593Smuzhiyun 	pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, BIOSImageBus | 0x1);
424*4882a593Smuzhiyun #endif
425*4882a593Smuzhiyun 	udelay(1);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	/*Check that the BIOS image is valid. If not fail, or return the
428*4882a593Smuzhiyun 	 compiled in BIOS image if that option was enabled
429*4882a593Smuzhiyun 	 */
430*4882a593Smuzhiyun 	if (BIOSImage[0] != 0x55 || BIOSImage[1] != 0xAA || BIOSImage[2] == 0) {
431*4882a593Smuzhiyun 		return NULL;
432*4882a593Smuzhiyun 	}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	return BIOSImage;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun /****************************************************************************
438*4882a593Smuzhiyun PARAMETERS:
439*4882a593Smuzhiyun pcidev	- PCI device info for the video card on the bus
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun REMARKS:
442*4882a593Smuzhiyun Unmaps the BIOS image for the device and restores framebuffer mappings
443*4882a593Smuzhiyun ****************************************************************************/
444*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
PCI_unmapBIOSImage(struct udevice * pcidev,void * BIOSImage)445*4882a593Smuzhiyun void PCI_unmapBIOSImage(struct udevice *pcidev, void *BIOSImage)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun 	dm_pci_write_config32(pcidev, PCI_ROM_ADDRESS, saveROMBaseAddress);
448*4882a593Smuzhiyun 	dm_pci_write_config32(pcidev, PCI_BASE_ADDRESS_0, saveBaseAddress10);
449*4882a593Smuzhiyun 	dm_pci_write_config32(pcidev, PCI_BASE_ADDRESS_1, saveBaseAddress14);
450*4882a593Smuzhiyun 	dm_pci_write_config32(pcidev, PCI_BASE_ADDRESS_2, saveBaseAddress18);
451*4882a593Smuzhiyun 	dm_pci_write_config32(pcidev, PCI_BASE_ADDRESS_4, saveBaseAddress20);
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun #else
PCI_unmapBIOSImage(pci_dev_t pcidev,void * BIOSImage)454*4882a593Smuzhiyun void PCI_unmapBIOSImage(pci_dev_t pcidev, void *BIOSImage)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, saveROMBaseAddress);
457*4882a593Smuzhiyun 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_0, saveBaseAddress10);
458*4882a593Smuzhiyun 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_1, saveBaseAddress14);
459*4882a593Smuzhiyun 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_2, saveBaseAddress18);
460*4882a593Smuzhiyun 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_4, saveBaseAddress20);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun #endif
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun /****************************************************************************
465*4882a593Smuzhiyun PARAMETERS:
466*4882a593Smuzhiyun pcidev	- PCI device info for the video card on the bus to boot
467*4882a593Smuzhiyun VGAInfo - BIOS emulator VGA info structure
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun RETURNS:
470*4882a593Smuzhiyun true if successfully initialised, false if not.
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun REMARKS:
473*4882a593Smuzhiyun Loads and POST's the display controllers BIOS, directly from the BIOS
474*4882a593Smuzhiyun image we can extract over the PCI bus.
475*4882a593Smuzhiyun ****************************************************************************/
476*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
PCI_postController(struct udevice * pcidev,uchar * bios_rom,int bios_len,BE_VGAInfo * vga_info,int vesa_mode,struct vbe_mode_info * mode_info)477*4882a593Smuzhiyun static int PCI_postController(struct udevice *pcidev, uchar *bios_rom,
478*4882a593Smuzhiyun 			      int bios_len, BE_VGAInfo *vga_info,
479*4882a593Smuzhiyun 			      int vesa_mode, struct vbe_mode_info *mode_info)
480*4882a593Smuzhiyun #else
481*4882a593Smuzhiyun static int PCI_postController(pci_dev_t pcidev, uchar *bios_rom, int bios_len,
482*4882a593Smuzhiyun 			      BE_VGAInfo *vga_info, int vesa_mode,
483*4882a593Smuzhiyun 			      struct vbe_mode_info *mode_info)
484*4882a593Smuzhiyun #endif
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun 	u32 bios_image_len;
487*4882a593Smuzhiyun 	uchar *mapped_bios;
488*4882a593Smuzhiyun 	uchar *copy_of_bios;
489*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
490*4882a593Smuzhiyun 	pci_dev_t bdf;
491*4882a593Smuzhiyun #endif
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	if (bios_rom) {
494*4882a593Smuzhiyun 		copy_of_bios = bios_rom;
495*4882a593Smuzhiyun 		bios_image_len = bios_len;
496*4882a593Smuzhiyun 	} else {
497*4882a593Smuzhiyun 		/*
498*4882a593Smuzhiyun 		 * Allocate memory to store copy of BIOS from display
499*4882a593Smuzhiyun 		 * controller
500*4882a593Smuzhiyun 		 */
501*4882a593Smuzhiyun 		mapped_bios = PCI_mapBIOSImage(pcidev);
502*4882a593Smuzhiyun 		if (mapped_bios == NULL) {
503*4882a593Smuzhiyun 			printf("videoboot: Video ROM failed to map!\n");
504*4882a593Smuzhiyun 			return false;
505*4882a593Smuzhiyun 		}
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 		bios_image_len = mapped_bios[2] * 512;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 		copy_of_bios = malloc(bios_image_len);
510*4882a593Smuzhiyun 		if (copy_of_bios == NULL) {
511*4882a593Smuzhiyun 			printf("videoboot: Out of memory!\n");
512*4882a593Smuzhiyun 			return false;
513*4882a593Smuzhiyun 		}
514*4882a593Smuzhiyun 		memcpy(copy_of_bios, mapped_bios, bios_image_len);
515*4882a593Smuzhiyun 		PCI_unmapBIOSImage(pcidev, mapped_bios);
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	/*Save information in vga_info structure*/
519*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
520*4882a593Smuzhiyun 	bdf = dm_pci_get_bdf(pcidev);
521*4882a593Smuzhiyun 	vga_info->function = PCI_FUNC(bdf);
522*4882a593Smuzhiyun 	vga_info->device = PCI_DEV(bdf);
523*4882a593Smuzhiyun 	vga_info->bus = PCI_BUS(bdf);
524*4882a593Smuzhiyun #else
525*4882a593Smuzhiyun 	vga_info->function = PCI_FUNC(pcidev);
526*4882a593Smuzhiyun 	vga_info->device = PCI_DEV(pcidev);
527*4882a593Smuzhiyun 	vga_info->bus = PCI_BUS(pcidev);
528*4882a593Smuzhiyun #endif
529*4882a593Smuzhiyun 	vga_info->pcidev = pcidev;
530*4882a593Smuzhiyun 	vga_info->BIOSImage = copy_of_bios;
531*4882a593Smuzhiyun 	vga_info->BIOSImageLen = bios_image_len;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	/*Now execute the BIOS POST for the device*/
534*4882a593Smuzhiyun 	if (copy_of_bios[0] != 0x55 || copy_of_bios[1] != 0xAA) {
535*4882a593Smuzhiyun 		printf("videoboot: Video ROM image is invalid!\n");
536*4882a593Smuzhiyun 		return false;
537*4882a593Smuzhiyun 	}
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	PCI_doBIOSPOST(pcidev, vga_info, vesa_mode, mode_info);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	/*Reset the size of the BIOS image to the final size*/
542*4882a593Smuzhiyun 	vga_info->BIOSImageLen = copy_of_bios[2] * 512;
543*4882a593Smuzhiyun 	return true;
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
biosemu_setup(struct udevice * pcidev,BE_VGAInfo ** vga_infop)547*4882a593Smuzhiyun int biosemu_setup(struct udevice *pcidev, BE_VGAInfo **vga_infop)
548*4882a593Smuzhiyun #else
549*4882a593Smuzhiyun int biosemu_setup(pci_dev_t pcidev, BE_VGAInfo **vga_infop)
550*4882a593Smuzhiyun #endif
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun 	BE_VGAInfo *VGAInfo;
553*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
554*4882a593Smuzhiyun 	pci_dev_t bdf = dm_pci_get_bdf(pcidev);
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	printf("videoboot: Booting PCI video card bus %d, function %d, device %d\n",
557*4882a593Smuzhiyun 	       PCI_BUS(bdf), PCI_FUNC(bdf), PCI_DEV(bdf));
558*4882a593Smuzhiyun #else
559*4882a593Smuzhiyun 	printf("videoboot: Booting PCI video card bus %d, function %d, device %d\n",
560*4882a593Smuzhiyun 	       PCI_BUS(pcidev), PCI_FUNC(pcidev), PCI_DEV(pcidev));
561*4882a593Smuzhiyun #endif
562*4882a593Smuzhiyun 	/*Initialise the x86 BIOS emulator*/
563*4882a593Smuzhiyun 	if ((VGAInfo = malloc(sizeof(*VGAInfo))) == NULL) {
564*4882a593Smuzhiyun 		printf("videoboot: Out of memory!\n");
565*4882a593Smuzhiyun 		return -ENOMEM;
566*4882a593Smuzhiyun 	}
567*4882a593Smuzhiyun 	memset(VGAInfo, 0, sizeof(*VGAInfo));
568*4882a593Smuzhiyun 	BE_init(0, 65536, VGAInfo, 0);
569*4882a593Smuzhiyun 	*vga_infop = VGAInfo;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	return 0;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun 
biosemu_set_interrupt_handler(int intnum,int (* int_func)(void))574*4882a593Smuzhiyun void biosemu_set_interrupt_handler(int intnum, int (*int_func)(void))
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun 	X86EMU_setupIntrFunc(intnum, (X86EMU_intrFuncs)int_func);
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
biosemu_run(struct udevice * pcidev,uchar * bios_rom,int bios_len,BE_VGAInfo * vga_info,int clean_up,int vesa_mode,struct vbe_mode_info * mode_info)580*4882a593Smuzhiyun int biosemu_run(struct udevice *pcidev, uchar *bios_rom, int bios_len,
581*4882a593Smuzhiyun 		BE_VGAInfo *vga_info, int clean_up, int vesa_mode,
582*4882a593Smuzhiyun 		struct vbe_mode_info *mode_info)
583*4882a593Smuzhiyun #else
584*4882a593Smuzhiyun int biosemu_run(pci_dev_t pcidev, uchar *bios_rom, int bios_len,
585*4882a593Smuzhiyun 		BE_VGAInfo *vga_info, int clean_up, int vesa_mode,
586*4882a593Smuzhiyun 		struct vbe_mode_info *mode_info)
587*4882a593Smuzhiyun #endif
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	/*Post all the display controller BIOS'es*/
590*4882a593Smuzhiyun 	if (!PCI_postController(pcidev, bios_rom, bios_len, vga_info,
591*4882a593Smuzhiyun 				vesa_mode, mode_info))
592*4882a593Smuzhiyun 		return -EINVAL;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	/*
595*4882a593Smuzhiyun 	 * Cleanup and exit the emulator if requested. If the BIOS emulator
596*4882a593Smuzhiyun 	 * is needed after booting the card, we will not call BE_exit and
597*4882a593Smuzhiyun 	 * leave it enabled for further use (ie: VESA driver etc).
598*4882a593Smuzhiyun 	*/
599*4882a593Smuzhiyun 	if (clean_up) {
600*4882a593Smuzhiyun 		BE_exit();
601*4882a593Smuzhiyun 		if (vga_info->BIOSImage &&
602*4882a593Smuzhiyun 		    (ulong)(vga_info->BIOSImage) != 0xc0000)
603*4882a593Smuzhiyun 			free(vga_info->BIOSImage);
604*4882a593Smuzhiyun 		free(vga_info);
605*4882a593Smuzhiyun 		vga_info = NULL;
606*4882a593Smuzhiyun 	}
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	return 0;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun /****************************************************************************
612*4882a593Smuzhiyun PARAMETERS:
613*4882a593Smuzhiyun pcidev	    - PCI device info for the video card on the bus to boot
614*4882a593Smuzhiyun pVGAInfo    - Place to return VGA info structure is requested
615*4882a593Smuzhiyun cleanUp	    - true to clean up on exit, false to leave emulator active
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun REMARKS:
618*4882a593Smuzhiyun Boots the PCI/AGP video card on the bus using the Video ROM BIOS image
619*4882a593Smuzhiyun and the X86 BIOS emulator module.
620*4882a593Smuzhiyun ****************************************************************************/
621*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
BootVideoCardBIOS(struct udevice * pcidev,BE_VGAInfo ** pVGAInfo,int clean_up)622*4882a593Smuzhiyun int BootVideoCardBIOS(struct udevice *pcidev, BE_VGAInfo **pVGAInfo,
623*4882a593Smuzhiyun 		      int clean_up)
624*4882a593Smuzhiyun #else
625*4882a593Smuzhiyun int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo **pVGAInfo, int clean_up)
626*4882a593Smuzhiyun #endif
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	BE_VGAInfo *VGAInfo;
629*4882a593Smuzhiyun 	int ret;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	ret = biosemu_setup(pcidev, &VGAInfo);
632*4882a593Smuzhiyun 	if (ret)
633*4882a593Smuzhiyun 		return false;
634*4882a593Smuzhiyun 	ret = biosemu_run(pcidev, NULL, 0, VGAInfo, clean_up, -1, NULL);
635*4882a593Smuzhiyun 	if (ret)
636*4882a593Smuzhiyun 		return false;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	/* Return VGA info pointer if the caller requested it*/
639*4882a593Smuzhiyun 	if (pVGAInfo)
640*4882a593Smuzhiyun 		*pVGAInfo = VGAInfo;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	return true;
643*4882a593Smuzhiyun }
644