xref: /rk3399_rockchip-uboot/drivers/bios_emulator/atibios.c (revision 5ebd27d860ec0c6e36f1b0f973653fe66a7360be)
1ece92f85SJason Jin /****************************************************************************
2ece92f85SJason Jin *
3ece92f85SJason Jin *		     Video BOOT Graphics Card POST Module
4ece92f85SJason Jin *
5ece92f85SJason Jin *  ========================================================================
64c2e3da8SKumar Gala *   Copyright (C) 2007 Freescale Semiconductor, Inc.
7ece92f85SJason Jin *   Jason Jin <Jason.jin@freescale.com>
8ece92f85SJason Jin *
9ece92f85SJason Jin *   Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
10ece92f85SJason Jin *
11ece92f85SJason Jin *   This file may be distributed and/or modified under the terms of the
12ece92f85SJason Jin *   GNU General Public License version 2.0 as published by the Free
13ece92f85SJason Jin *   Software Foundation and appearing in the file LICENSE.GPL included
14ece92f85SJason Jin *   in the packaging of this file.
15ece92f85SJason Jin *
16ece92f85SJason Jin *   Licensees holding a valid Commercial License for this product from
17ece92f85SJason Jin *   SciTech Software, Inc. may use this file in accordance with the
18ece92f85SJason Jin *   Commercial License Agreement provided with the Software.
19ece92f85SJason Jin *
20ece92f85SJason Jin *   This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
21ece92f85SJason Jin *   THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22ece92f85SJason Jin *   PURPOSE.
23ece92f85SJason Jin *
24ece92f85SJason Jin *   See http://www.scitechsoft.com/license/ for information about
25ece92f85SJason Jin *   the licensing options available and how to purchase a Commercial
26ece92f85SJason Jin *   License Agreement.
27ece92f85SJason Jin *
28ece92f85SJason Jin *   Contact license@scitechsoft.com if any conditions of this licensing
29ece92f85SJason Jin *   are not clear to you, or you have questions about licensing options.
30ece92f85SJason Jin *
31ece92f85SJason Jin *  ========================================================================
32ece92f85SJason Jin *
33ece92f85SJason Jin * Language:	ANSI C
34ece92f85SJason Jin * Environment:	Linux Kernel
35ece92f85SJason Jin * Developer:	Kendall Bennett
36ece92f85SJason Jin *
37ece92f85SJason Jin * Description:	Module to implement booting PCI/AGP controllers on the
38ece92f85SJason Jin *		bus. We use the x86 real mode emulator to run the BIOS on
39ece92f85SJason Jin *		graphics controllers to bring the cards up.
40ece92f85SJason Jin *
41ece92f85SJason Jin *		Note that at present this module does *not* support
42ece92f85SJason Jin *		multiple controllers.
43ece92f85SJason Jin *
44ece92f85SJason Jin *		The orignal name of this file is warmboot.c.
45ece92f85SJason Jin *		Jason ported this file to u-boot to run the ATI video card
46ece92f85SJason Jin *		BIOS in u-boot.
47ece92f85SJason Jin ****************************************************************************/
48ece92f85SJason Jin #include <common.h>
494c59f953SSimon Glass #include <bios_emul.h>
504c59f953SSimon Glass #include <errno.h>
51ece92f85SJason Jin #include <malloc.h>
524c59f953SSimon Glass #include <vbe.h>
534c59f953SSimon Glass #include "biosemui.h"
54ece92f85SJason Jin 
55ece92f85SJason Jin /* Length of the BIOS image */
56ece92f85SJason Jin #define MAX_BIOSLEN	    (128 * 1024L)
57ece92f85SJason Jin 
58ece92f85SJason Jin /* Place to save PCI BAR's that we change and later restore */
59ece92f85SJason Jin static u32 saveROMBaseAddress;
60ece92f85SJason Jin static u32 saveBaseAddress10;
61ece92f85SJason Jin static u32 saveBaseAddress14;
62ece92f85SJason Jin static u32 saveBaseAddress18;
63ece92f85SJason Jin static u32 saveBaseAddress20;
64ece92f85SJason Jin 
65222f25f8SSimon Glass /* Addres im memory of VBE region */
66222f25f8SSimon Glass const int vbe_offset = 0x2000;
67222f25f8SSimon Glass 
bios_ptr(const void * buf,BE_VGAInfo * vga_info,u32 x86_dword_ptr)68222f25f8SSimon Glass static const void *bios_ptr(const void *buf, BE_VGAInfo *vga_info,
69222f25f8SSimon Glass 			    u32 x86_dword_ptr)
704c59f953SSimon Glass {
71222f25f8SSimon Glass 	u32 seg_ofs, flat;
72222f25f8SSimon Glass 
73222f25f8SSimon Glass 	seg_ofs = le32_to_cpu(x86_dword_ptr);
74222f25f8SSimon Glass 	flat = ((seg_ofs & 0xffff0000) >> 12) | (seg_ofs & 0xffff);
75222f25f8SSimon Glass 	if (flat >= 0xc0000)
76222f25f8SSimon Glass 		return vga_info->BIOSImage + flat - 0xc0000;
77222f25f8SSimon Glass 	else
78222f25f8SSimon Glass 		return buf + (flat - vbe_offset);
79222f25f8SSimon Glass }
80222f25f8SSimon Glass 
atibios_debug_mode(BE_VGAInfo * vga_info,RMREGS * regs,int vesa_mode,struct vbe_mode_info * mode_info)81222f25f8SSimon Glass static int atibios_debug_mode(BE_VGAInfo *vga_info, RMREGS *regs,
82222f25f8SSimon Glass 			      int vesa_mode, struct vbe_mode_info *mode_info)
83222f25f8SSimon Glass {
84222f25f8SSimon Glass 	void *buffer = (void *)(M.mem_base + vbe_offset);
85222f25f8SSimon Glass 	u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
86222f25f8SSimon Glass 	u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
87222f25f8SSimon Glass 	struct vesa_mode_info *vm;
88222f25f8SSimon Glass 	struct vbe_info *info;
89222f25f8SSimon Glass 	const u16 *modes_bios, *ptr;
90222f25f8SSimon Glass 	u16 *modes;
91222f25f8SSimon Glass 	int size;
92222f25f8SSimon Glass 
93222f25f8SSimon Glass 	debug("VBE: Getting information\n");
94222f25f8SSimon Glass 	regs->e.eax = VESA_GET_INFO;
95222f25f8SSimon Glass 	regs->e.esi = buffer_seg;
96222f25f8SSimon Glass 	regs->e.edi = buffer_adr;
97222f25f8SSimon Glass 	info = buffer;
98222f25f8SSimon Glass 	memset(info, '\0', sizeof(*info));
99222f25f8SSimon Glass 	strcpy(info->signature, "VBE2");
1004c59f953SSimon Glass 	BE_int86(0x10, regs, regs);
101222f25f8SSimon Glass 	if (regs->e.eax != 0x4f) {
102222f25f8SSimon Glass 		debug("VESA_GET_INFO: error %x\n", regs->e.eax);
103222f25f8SSimon Glass 		return -ENOSYS;
104222f25f8SSimon Glass 	}
105222f25f8SSimon Glass 	debug("version %x\n", le16_to_cpu(info->version));
106222f25f8SSimon Glass 	debug("oem '%s'\n", (char *)bios_ptr(buffer, vga_info,
107222f25f8SSimon Glass 					     info->oem_string_ptr));
108222f25f8SSimon Glass 	debug("vendor '%s'\n", (char *)bios_ptr(buffer, vga_info,
109222f25f8SSimon Glass 						info->vendor_name_ptr));
110222f25f8SSimon Glass 	debug("product '%s'\n", (char *)bios_ptr(buffer, vga_info,
111222f25f8SSimon Glass 						 info->product_name_ptr));
112222f25f8SSimon Glass 	debug("rev '%s'\n", (char *)bios_ptr(buffer, vga_info,
113222f25f8SSimon Glass 					     info->product_rev_ptr));
114222f25f8SSimon Glass 	modes_bios = bios_ptr(buffer, vga_info, info->modes_ptr);
115222f25f8SSimon Glass 	debug("Modes: ");
116222f25f8SSimon Glass 	for (ptr = modes_bios; *ptr != 0xffff; ptr++)
117222f25f8SSimon Glass 		debug("%x ", le16_to_cpu(*ptr));
118222f25f8SSimon Glass 	debug("\nmemory %dMB\n", le16_to_cpu(info->total_memory) >> 4);
119222f25f8SSimon Glass 	size = (ptr - modes_bios) * sizeof(u16) + 2;
120222f25f8SSimon Glass 	modes = malloc(size);
121222f25f8SSimon Glass 	if (!modes)
122222f25f8SSimon Glass 		return -ENOMEM;
123222f25f8SSimon Glass 	memcpy(modes, modes_bios, size);
1244c59f953SSimon Glass 
125222f25f8SSimon Glass 	regs->e.eax = VESA_GET_CUR_MODE;
126222f25f8SSimon Glass 	BE_int86(0x10, regs, regs);
127222f25f8SSimon Glass 	if (regs->e.eax != 0x4f) {
128222f25f8SSimon Glass 		debug("VESA_GET_CUR_MODE: error %x\n", regs->e.eax);
129222f25f8SSimon Glass 		return -ENOSYS;
130222f25f8SSimon Glass 	}
131222f25f8SSimon Glass 	debug("Current mode %x\n", regs->e.ebx);
1324c59f953SSimon Glass 
133222f25f8SSimon Glass 	for (ptr = modes; *ptr != 0xffff; ptr++) {
134222f25f8SSimon Glass 		int mode = le16_to_cpu(*ptr);
135222f25f8SSimon Glass 		bool linear_ok;
136222f25f8SSimon Glass 		int attr;
137222f25f8SSimon Glass 
138222f25f8SSimon Glass 		break;
139222f25f8SSimon Glass 		debug("Mode %x: ", mode);
140222f25f8SSimon Glass 		memset(buffer, '\0', sizeof(struct vbe_mode_info));
1414c59f953SSimon Glass 		regs->e.eax = VESA_GET_MODE_INFO;
1424c59f953SSimon Glass 		regs->e.ebx = 0;
143222f25f8SSimon Glass 		regs->e.ecx = mode;
1444c59f953SSimon Glass 		regs->e.edx = 0;
1454c59f953SSimon Glass 		regs->e.esi = buffer_seg;
1464c59f953SSimon Glass 		regs->e.edi = buffer_adr;
1474c59f953SSimon Glass 		BE_int86(0x10, regs, regs);
148222f25f8SSimon Glass 		if (regs->e.eax != 0x4f) {
149222f25f8SSimon Glass 			debug("VESA_GET_MODE_INFO: error %x\n", regs->e.eax);
150222f25f8SSimon Glass 			continue;
151222f25f8SSimon Glass 		}
1524c59f953SSimon Glass 		memcpy(mode_info->mode_info_block, buffer,
153222f25f8SSimon Glass 		       sizeof(struct vesa_mode_info));
1544c59f953SSimon Glass 		mode_info->valid = true;
155222f25f8SSimon Glass 		vm = &mode_info->vesa;
156222f25f8SSimon Glass 		attr = le16_to_cpu(vm->mode_attributes);
157222f25f8SSimon Glass 		linear_ok = attr & 0x80;
158222f25f8SSimon Glass 		debug("res %d x %d, %d bpp, mm %d, (Linear %s, attr %02x)\n",
159222f25f8SSimon Glass 		      le16_to_cpu(vm->x_resolution),
160222f25f8SSimon Glass 		      le16_to_cpu(vm->y_resolution),
161222f25f8SSimon Glass 		      vm->bits_per_pixel, vm->memory_model,
162222f25f8SSimon Glass 		      linear_ok ? "OK" : "not available",
163222f25f8SSimon Glass 		      attr);
164222f25f8SSimon Glass 		debug("\tRGB pos=%d,%d,%d, size=%d,%d,%d\n",
165222f25f8SSimon Glass 		      vm->red_mask_pos, vm->green_mask_pos, vm->blue_mask_pos,
166222f25f8SSimon Glass 		      vm->red_mask_size, vm->green_mask_size,
167222f25f8SSimon Glass 		      vm->blue_mask_size);
168222f25f8SSimon Glass 	}
1694c59f953SSimon Glass 
170222f25f8SSimon Glass 	return 0;
171222f25f8SSimon Glass }
172222f25f8SSimon Glass 
atibios_set_vesa_mode(RMREGS * regs,int vesa_mode,struct vbe_mode_info * mode_info)173222f25f8SSimon Glass static int atibios_set_vesa_mode(RMREGS *regs, int vesa_mode,
174222f25f8SSimon Glass 				 struct vbe_mode_info *mode_info)
175222f25f8SSimon Glass {
176222f25f8SSimon Glass 	void *buffer = (void *)(M.mem_base + vbe_offset);
177222f25f8SSimon Glass 	u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
178222f25f8SSimon Glass 	u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
179222f25f8SSimon Glass 	struct vesa_mode_info *vm;
180222f25f8SSimon Glass 
181222f25f8SSimon Glass 	debug("VBE: Setting VESA mode %#04x\n", vesa_mode);
1824c59f953SSimon Glass 	regs->e.eax = VESA_SET_MODE;
1834c59f953SSimon Glass 	regs->e.ebx = vesa_mode;
184222f25f8SSimon Glass 	/* request linear framebuffer mode and don't clear display */
185222f25f8SSimon Glass 	regs->e.ebx |= (1 << 14) | (1 << 15);
1864c59f953SSimon Glass 	BE_int86(0x10, regs, regs);
187222f25f8SSimon Glass 	if (regs->e.eax != 0x4f) {
188222f25f8SSimon Glass 		debug("VESA_SET_MODE: error %x\n", regs->e.eax);
189222f25f8SSimon Glass 		return -ENOSYS;
190222f25f8SSimon Glass 	}
191222f25f8SSimon Glass 
192222f25f8SSimon Glass 	memset(buffer, '\0', sizeof(struct vbe_mode_info));
193222f25f8SSimon Glass 	debug("VBE: Geting info for VESA mode %#04x\n", vesa_mode);
194222f25f8SSimon Glass 	regs->e.eax = VESA_GET_MODE_INFO;
195222f25f8SSimon Glass 	regs->e.ecx = vesa_mode;
196222f25f8SSimon Glass 	regs->e.esi = buffer_seg;
197222f25f8SSimon Glass 	regs->e.edi = buffer_adr;
198222f25f8SSimon Glass 	BE_int86(0x10, regs, regs);
199222f25f8SSimon Glass 	if (regs->e.eax != 0x4f) {
200222f25f8SSimon Glass 		debug("VESA_GET_MODE_INFO: error %x\n", regs->e.eax);
201222f25f8SSimon Glass 		return -ENOSYS;
202222f25f8SSimon Glass 	}
203222f25f8SSimon Glass 
204222f25f8SSimon Glass 	memcpy(mode_info->mode_info_block, buffer,
205222f25f8SSimon Glass 		sizeof(struct vesa_mode_info));
206222f25f8SSimon Glass 	mode_info->valid = true;
207222f25f8SSimon Glass 	mode_info->video_mode = vesa_mode;
208222f25f8SSimon Glass 	vm = &mode_info->vesa;
209222f25f8SSimon Glass 	vm->x_resolution = le16_to_cpu(vm->x_resolution);
210222f25f8SSimon Glass 	vm->y_resolution = le16_to_cpu(vm->y_resolution);
211222f25f8SSimon Glass 	vm->bytes_per_scanline = le16_to_cpu(vm->bytes_per_scanline);
212222f25f8SSimon Glass 	vm->phys_base_ptr = le32_to_cpu(vm->phys_base_ptr);
213222f25f8SSimon Glass 	vm->mode_attributes = le16_to_cpu(vm->mode_attributes);
214222f25f8SSimon Glass 	debug("VBE: Init complete\n");
215222f25f8SSimon Glass 
216222f25f8SSimon Glass 	return 0;
2174c59f953SSimon Glass }
2184c59f953SSimon Glass 
219ece92f85SJason Jin /****************************************************************************
220ece92f85SJason Jin PARAMETERS:
221ece92f85SJason Jin pcidev	- PCI device info for the video card on the bus to boot
2224c59f953SSimon Glass vga_info - BIOS emulator VGA info structure
223ece92f85SJason Jin 
224ece92f85SJason Jin REMARKS:
225ece92f85SJason Jin This function executes the BIOS POST code on the controller. We assume that
226ece92f85SJason Jin at this stage the controller has its I/O and memory space enabled and
227ece92f85SJason Jin that all other controllers are in a disabled state.
228ece92f85SJason Jin ****************************************************************************/
2297282672dSSimon Glass #ifdef CONFIG_DM_PCI
PCI_doBIOSPOST(struct udevice * pcidev,BE_VGAInfo * vga_info,int vesa_mode,struct vbe_mode_info * mode_info)2307282672dSSimon Glass static void PCI_doBIOSPOST(struct udevice *pcidev, BE_VGAInfo *vga_info,
2317282672dSSimon Glass 			   int vesa_mode, struct vbe_mode_info *mode_info)
2327282672dSSimon Glass #else
2334c59f953SSimon Glass static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo *vga_info,
2344c59f953SSimon Glass 			   int vesa_mode, struct vbe_mode_info *mode_info)
2357282672dSSimon Glass #endif
236ece92f85SJason Jin {
237ece92f85SJason Jin 	RMREGS regs;
238ece92f85SJason Jin 	RMSREGS sregs;
2397282672dSSimon Glass #ifdef CONFIG_DM_PCI
2407282672dSSimon Glass 	pci_dev_t bdf;
2417282672dSSimon Glass #endif
242ece92f85SJason Jin 
243ece92f85SJason Jin 	/* Determine the value to store in AX for BIOS POST. Per the PCI specs,
244ece92f85SJason Jin 	 AH must contain the bus and AL must contain the devfn, encoded as
245ece92f85SJason Jin 	 (dev << 3) | fn
246ece92f85SJason Jin 	 */
247ece92f85SJason Jin 	memset(&regs, 0, sizeof(regs));
248ece92f85SJason Jin 	memset(&sregs, 0, sizeof(sregs));
2497282672dSSimon Glass #ifdef CONFIG_DM_PCI
2507282672dSSimon Glass 	bdf = dm_pci_get_bdf(pcidev);
2517282672dSSimon Glass 	regs.x.ax = (int)PCI_BUS(bdf) << 8 |
2527282672dSSimon Glass 			(int)PCI_DEV(bdf) << 3 | (int)PCI_FUNC(bdf);
2537282672dSSimon Glass #else
254ece92f85SJason Jin 	regs.x.ax = ((int)PCI_BUS(pcidev) << 8) |
255ece92f85SJason Jin 	    ((int)PCI_DEV(pcidev) << 3) | (int)PCI_FUNC(pcidev);
2567282672dSSimon Glass #endif
257ece92f85SJason Jin 	/*Setup the X86 emulator for the VGA BIOS*/
2584c59f953SSimon Glass 	BE_setVGA(vga_info);
259ece92f85SJason Jin 
260ece92f85SJason Jin 	/*Execute the BIOS POST code*/
261ece92f85SJason Jin 	BE_callRealMode(0xC000, 0x0003, &regs, &sregs);
262ece92f85SJason Jin 
263ece92f85SJason Jin 	/*Cleanup and exit*/
2644c59f953SSimon Glass 	BE_getVGA(vga_info);
2654c59f953SSimon Glass 
266222f25f8SSimon Glass 	/* Useful for debugging */
267222f25f8SSimon Glass 	if (0)
268222f25f8SSimon Glass 		atibios_debug_mode(vga_info, &regs, vesa_mode, mode_info);
2694c59f953SSimon Glass 	if (vesa_mode != -1)
2704c59f953SSimon Glass 		atibios_set_vesa_mode(&regs, vesa_mode, mode_info);
271ece92f85SJason Jin }
272ece92f85SJason Jin 
273ece92f85SJason Jin /****************************************************************************
274ece92f85SJason Jin PARAMETERS:
275ece92f85SJason Jin pcidev	- PCI device info for the video card on the bus
276ece92f85SJason Jin bar	- Place to return the base address register offset to use
277ece92f85SJason Jin 
278ece92f85SJason Jin RETURNS:
279ece92f85SJason Jin The address to use to map the secondary BIOS (AGP devices)
280ece92f85SJason Jin 
281ece92f85SJason Jin REMARKS:
282ece92f85SJason Jin Searches all the PCI base address registers for the device looking for a
283ece92f85SJason Jin memory mapping that is large enough to hold our ROM BIOS. We usually end up
284ece92f85SJason Jin finding the framebuffer mapping (usually BAR 0x10), and we use this mapping
285ece92f85SJason Jin to map the BIOS for the device into. We use a mapping that is already
286ece92f85SJason Jin assigned to the device to ensure the memory range will be passed through
287ece92f85SJason Jin by any PCI->PCI or AGP->PCI bridge that may be present.
288ece92f85SJason Jin 
289ece92f85SJason Jin NOTE: Usually this function is only used for AGP devices, but it may be
290ece92f85SJason Jin       used for PCI devices that have already been POST'ed and the BIOS
291ece92f85SJason Jin       ROM base address has been zero'ed out.
292ece92f85SJason Jin 
293ece92f85SJason Jin NOTE: This function leaves the original memory aperture disabled by leaving
294ece92f85SJason Jin       it programmed to all 1's. It must be restored to the correct value
295ece92f85SJason Jin       later.
296ece92f85SJason Jin ****************************************************************************/
2977282672dSSimon Glass #ifdef CONFIG_DM_PCI
PCI_findBIOSAddr(struct udevice * pcidev,int * bar)2987282672dSSimon Glass static u32 PCI_findBIOSAddr(struct udevice *pcidev, int *bar)
2997282672dSSimon Glass #else
300ece92f85SJason Jin static u32 PCI_findBIOSAddr(pci_dev_t pcidev, int *bar)
3017282672dSSimon Glass #endif
302ece92f85SJason Jin {
303ece92f85SJason Jin 	u32 base, size;
304ece92f85SJason Jin 
305ece92f85SJason Jin 	for (*bar = 0x10; *bar <= 0x14; (*bar) += 4) {
3067282672dSSimon Glass #ifdef CONFIG_DM_PCI
3077282672dSSimon Glass 		dm_pci_read_config32(pcidev, *bar, &base);
3087282672dSSimon Glass #else
309ece92f85SJason Jin 		pci_read_config_dword(pcidev, *bar, &base);
3107282672dSSimon Glass #endif
311ece92f85SJason Jin 		if (!(base & 0x1)) {
3127282672dSSimon Glass #ifdef CONFIG_DM_PCI
3137282672dSSimon Glass 			dm_pci_write_config32(pcidev, *bar, 0xFFFFFFFF);
3147282672dSSimon Glass 			dm_pci_read_config32(pcidev, *bar, &size);
3157282672dSSimon Glass #else
316ece92f85SJason Jin 			pci_write_config_dword(pcidev, *bar, 0xFFFFFFFF);
317ece92f85SJason Jin 			pci_read_config_dword(pcidev, *bar, &size);
3187282672dSSimon Glass #endif
319ece92f85SJason Jin 			size = ~(size & ~0xFF) + 1;
320ece92f85SJason Jin 			if (size >= MAX_BIOSLEN)
321ece92f85SJason Jin 				return base & ~0xFF;
322ece92f85SJason Jin 		}
323ece92f85SJason Jin 	}
324ece92f85SJason Jin 	return 0;
325ece92f85SJason Jin }
326ece92f85SJason Jin 
327ece92f85SJason Jin /****************************************************************************
328ece92f85SJason Jin REMARKS:
329ece92f85SJason Jin Some non-x86 Linux kernels map PCI relocateable I/O to values that
330ece92f85SJason Jin are above 64K, which will not work with the BIOS image that requires
331ece92f85SJason Jin the offset for the I/O ports to be a maximum of 16-bits. Ideally
332ece92f85SJason Jin someone should fix the kernel to map the I/O ports for VGA compatible
333ece92f85SJason Jin devices to a different location (or just all I/O ports since it is
334ece92f85SJason Jin unlikely you can have enough devices in the machine to use up all
335ece92f85SJason Jin 64K of the I/O space - a total of more than 256 cards would be
336ece92f85SJason Jin necessary).
337ece92f85SJason Jin 
338ece92f85SJason Jin Anyway to fix this we change all I/O mapped base registers and
339ece92f85SJason Jin chop off the top bits.
340ece92f85SJason Jin ****************************************************************************/
3417282672dSSimon Glass #ifdef CONFIG_DM_PCI
PCI_fixupIObase(struct udevice * pcidev,int reg,u32 * base)3427282672dSSimon Glass static void PCI_fixupIObase(struct udevice *pcidev, int reg, u32 *base)
3437282672dSSimon Glass #else
344ece92f85SJason Jin static void PCI_fixupIObase(pci_dev_t pcidev, int reg, u32 * base)
3457282672dSSimon Glass #endif
346ece92f85SJason Jin {
347ece92f85SJason Jin 	if ((*base & 0x1) && (*base > 0xFFFE)) {
348ece92f85SJason Jin 		*base &= 0xFFFF;
3497282672dSSimon Glass #ifdef CONFIG_DM_PCI
3507282672dSSimon Glass 		dm_pci_write_config32(pcidev, reg, *base);
3517282672dSSimon Glass #else
352ece92f85SJason Jin 		pci_write_config_dword(pcidev, reg, *base);
3537282672dSSimon Glass #endif
354ece92f85SJason Jin 
355ece92f85SJason Jin 	}
356ece92f85SJason Jin }
357ece92f85SJason Jin 
358ece92f85SJason Jin /****************************************************************************
359ece92f85SJason Jin PARAMETERS:
360ece92f85SJason Jin pcidev	- PCI device info for the video card on the bus
361ece92f85SJason Jin 
362ece92f85SJason Jin RETURNS:
363ece92f85SJason Jin Pointers to the mapped BIOS image
364ece92f85SJason Jin 
365ece92f85SJason Jin REMARKS:
366ece92f85SJason Jin Maps a pointer to the BIOS image on the graphics card on the PCI bus.
367ece92f85SJason Jin ****************************************************************************/
3687282672dSSimon Glass #ifdef CONFIG_DM_PCI
PCI_mapBIOSImage(struct udevice * pcidev)3697282672dSSimon Glass void *PCI_mapBIOSImage(struct udevice *pcidev)
3707282672dSSimon Glass #else
371ece92f85SJason Jin void *PCI_mapBIOSImage(pci_dev_t pcidev)
3727282672dSSimon Glass #endif
373ece92f85SJason Jin {
374f6a7a2e8SEd Swarthout 	u32 BIOSImageBus;
375ece92f85SJason Jin 	int BIOSImageBAR;
376ece92f85SJason Jin 	u8 *BIOSImage;
377ece92f85SJason Jin 
378ece92f85SJason Jin 	/*Save PCI BAR registers that might get changed*/
3797282672dSSimon Glass #ifdef CONFIG_DM_PCI
3807282672dSSimon Glass 	dm_pci_read_config32(pcidev, PCI_ROM_ADDRESS, &saveROMBaseAddress);
3817282672dSSimon Glass 	dm_pci_read_config32(pcidev, PCI_BASE_ADDRESS_0, &saveBaseAddress10);
3827282672dSSimon Glass 	dm_pci_read_config32(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14);
3837282672dSSimon Glass 	dm_pci_read_config32(pcidev, PCI_BASE_ADDRESS_2, &saveBaseAddress18);
3847282672dSSimon Glass 	dm_pci_read_config32(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20);
3857282672dSSimon Glass #else
386ece92f85SJason Jin 	pci_read_config_dword(pcidev, PCI_ROM_ADDRESS, &saveROMBaseAddress);
387ece92f85SJason Jin 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &saveBaseAddress10);
388ece92f85SJason Jin 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14);
389ece92f85SJason Jin 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_2, &saveBaseAddress18);
390ece92f85SJason Jin 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20);
3917282672dSSimon Glass #endif
392ece92f85SJason Jin 
393ece92f85SJason Jin 	/*Fix up I/O base registers to less than 64K */
394ece92f85SJason Jin 	if(saveBaseAddress14 != 0)
395ece92f85SJason Jin 		PCI_fixupIObase(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14);
396ece92f85SJason Jin 	else
397ece92f85SJason Jin 		PCI_fixupIObase(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20);
398ece92f85SJason Jin 
399ece92f85SJason Jin 	/* Some cards have problems that stop us from being able to read the
400ece92f85SJason Jin 	 BIOS image from the ROM BAR. To fix this we have to do some chipset
401ece92f85SJason Jin 	 specific programming for different cards to solve this problem.
402ece92f85SJason Jin 	*/
403ece92f85SJason Jin 
404f6a7a2e8SEd Swarthout 	BIOSImageBus = PCI_findBIOSAddr(pcidev, &BIOSImageBAR);
405f6a7a2e8SEd Swarthout 	if (BIOSImageBus == 0) {
406ece92f85SJason Jin 		printf("Find bios addr error\n");
407ece92f85SJason Jin 		return NULL;
408ece92f85SJason Jin 	}
409ece92f85SJason Jin 
4107282672dSSimon Glass #ifdef CONFIG_DM_PCI
4117282672dSSimon Glass 	BIOSImage = dm_pci_bus_to_virt(pcidev, BIOSImageBus,
4127282672dSSimon Glass 				       PCI_REGION_MEM, 0, MAP_NOCACHE);
4137282672dSSimon Glass 
4147282672dSSimon Glass 	/*Change the PCI BAR registers to map it onto the bus.*/
4157282672dSSimon Glass 	dm_pci_write_config32(pcidev, BIOSImageBAR, 0);
4167282672dSSimon Glass 	dm_pci_write_config32(pcidev, PCI_ROM_ADDRESS, BIOSImageBus | 0x1);
4177282672dSSimon Glass #else
418f6a7a2e8SEd Swarthout 	BIOSImage = pci_bus_to_virt(pcidev, BIOSImageBus,
419f6a7a2e8SEd Swarthout 				    PCI_REGION_MEM, 0, MAP_NOCACHE);
420ece92f85SJason Jin 
421ece92f85SJason Jin 	/*Change the PCI BAR registers to map it onto the bus.*/
422ece92f85SJason Jin 	pci_write_config_dword(pcidev, BIOSImageBAR, 0);
423f6a7a2e8SEd Swarthout 	pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, BIOSImageBus | 0x1);
4247282672dSSimon Glass #endif
425ece92f85SJason Jin 	udelay(1);
426ece92f85SJason Jin 
427ece92f85SJason Jin 	/*Check that the BIOS image is valid. If not fail, or return the
428ece92f85SJason Jin 	 compiled in BIOS image if that option was enabled
429ece92f85SJason Jin 	 */
430ece92f85SJason Jin 	if (BIOSImage[0] != 0x55 || BIOSImage[1] != 0xAA || BIOSImage[2] == 0) {
431ece92f85SJason Jin 		return NULL;
432ece92f85SJason Jin 	}
433ece92f85SJason Jin 
434ece92f85SJason Jin 	return BIOSImage;
435ece92f85SJason Jin }
436ece92f85SJason Jin 
437ece92f85SJason Jin /****************************************************************************
438ece92f85SJason Jin PARAMETERS:
439ece92f85SJason Jin pcidev	- PCI device info for the video card on the bus
440ece92f85SJason Jin 
441ece92f85SJason Jin REMARKS:
442ece92f85SJason Jin Unmaps the BIOS image for the device and restores framebuffer mappings
443ece92f85SJason Jin ****************************************************************************/
4447282672dSSimon Glass #ifdef CONFIG_DM_PCI
PCI_unmapBIOSImage(struct udevice * pcidev,void * BIOSImage)4457282672dSSimon Glass void PCI_unmapBIOSImage(struct udevice *pcidev, void *BIOSImage)
4467282672dSSimon Glass {
4477282672dSSimon Glass 	dm_pci_write_config32(pcidev, PCI_ROM_ADDRESS, saveROMBaseAddress);
4487282672dSSimon Glass 	dm_pci_write_config32(pcidev, PCI_BASE_ADDRESS_0, saveBaseAddress10);
4497282672dSSimon Glass 	dm_pci_write_config32(pcidev, PCI_BASE_ADDRESS_1, saveBaseAddress14);
4507282672dSSimon Glass 	dm_pci_write_config32(pcidev, PCI_BASE_ADDRESS_2, saveBaseAddress18);
4517282672dSSimon Glass 	dm_pci_write_config32(pcidev, PCI_BASE_ADDRESS_4, saveBaseAddress20);
4527282672dSSimon Glass }
4537282672dSSimon Glass #else
PCI_unmapBIOSImage(pci_dev_t pcidev,void * BIOSImage)454ece92f85SJason Jin void PCI_unmapBIOSImage(pci_dev_t pcidev, void *BIOSImage)
455ece92f85SJason Jin {
456ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, saveROMBaseAddress);
457ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_0, saveBaseAddress10);
458ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_1, saveBaseAddress14);
459ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_2, saveBaseAddress18);
460ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_4, saveBaseAddress20);
461ece92f85SJason Jin }
4627282672dSSimon Glass #endif
463ece92f85SJason Jin 
464ece92f85SJason Jin /****************************************************************************
465ece92f85SJason Jin PARAMETERS:
466ece92f85SJason Jin pcidev	- PCI device info for the video card on the bus to boot
467ece92f85SJason Jin VGAInfo - BIOS emulator VGA info structure
468ece92f85SJason Jin 
469ece92f85SJason Jin RETURNS:
470472d5460SYork Sun true if successfully initialised, false if not.
471ece92f85SJason Jin 
472ece92f85SJason Jin REMARKS:
473ece92f85SJason Jin Loads and POST's the display controllers BIOS, directly from the BIOS
474ece92f85SJason Jin image we can extract over the PCI bus.
475ece92f85SJason Jin ****************************************************************************/
4767282672dSSimon Glass #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)4777282672dSSimon Glass static int PCI_postController(struct udevice *pcidev, uchar *bios_rom,
4787282672dSSimon Glass 			      int bios_len, BE_VGAInfo *vga_info,
4797282672dSSimon Glass 			      int vesa_mode, struct vbe_mode_info *mode_info)
4807282672dSSimon Glass #else
4814c59f953SSimon Glass static int PCI_postController(pci_dev_t pcidev, uchar *bios_rom, int bios_len,
4824c59f953SSimon Glass 			      BE_VGAInfo *vga_info, int vesa_mode,
4834c59f953SSimon Glass 			      struct vbe_mode_info *mode_info)
4847282672dSSimon Glass #endif
485ece92f85SJason Jin {
4864c59f953SSimon Glass 	u32 bios_image_len;
4874c59f953SSimon Glass 	uchar *mapped_bios;
4884c59f953SSimon Glass 	uchar *copy_of_bios;
4897282672dSSimon Glass #ifdef CONFIG_DM_PCI
4907282672dSSimon Glass 	pci_dev_t bdf;
4917282672dSSimon Glass #endif
492ece92f85SJason Jin 
4934c59f953SSimon Glass 	if (bios_rom) {
4944c59f953SSimon Glass 		copy_of_bios = bios_rom;
4954c59f953SSimon Glass 		bios_image_len = bios_len;
4964c59f953SSimon Glass 	} else {
4974c59f953SSimon Glass 		/*
4984c59f953SSimon Glass 		 * Allocate memory to store copy of BIOS from display
4994c59f953SSimon Glass 		 * controller
5004c59f953SSimon Glass 		 */
5014c59f953SSimon Glass 		mapped_bios = PCI_mapBIOSImage(pcidev);
5024c59f953SSimon Glass 		if (mapped_bios == NULL) {
503ece92f85SJason Jin 			printf("videoboot: Video ROM failed to map!\n");
504ece92f85SJason Jin 			return false;
505ece92f85SJason Jin 		}
506ece92f85SJason Jin 
5074c59f953SSimon Glass 		bios_image_len = mapped_bios[2] * 512;
508ece92f85SJason Jin 
5094c59f953SSimon Glass 		copy_of_bios = malloc(bios_image_len);
5104c59f953SSimon Glass 		if (copy_of_bios == NULL) {
511ece92f85SJason Jin 			printf("videoboot: Out of memory!\n");
512ece92f85SJason Jin 			return false;
513ece92f85SJason Jin 		}
5144c59f953SSimon Glass 		memcpy(copy_of_bios, mapped_bios, bios_image_len);
5154c59f953SSimon Glass 		PCI_unmapBIOSImage(pcidev, mapped_bios);
5164c59f953SSimon Glass 	}
517ece92f85SJason Jin 
5184c59f953SSimon Glass 	/*Save information in vga_info structure*/
5197282672dSSimon Glass #ifdef CONFIG_DM_PCI
5207282672dSSimon Glass 	bdf = dm_pci_get_bdf(pcidev);
5217282672dSSimon Glass 	vga_info->function = PCI_FUNC(bdf);
5227282672dSSimon Glass 	vga_info->device = PCI_DEV(bdf);
5237282672dSSimon Glass 	vga_info->bus = PCI_BUS(bdf);
5247282672dSSimon Glass #else
5254c59f953SSimon Glass 	vga_info->function = PCI_FUNC(pcidev);
5264c59f953SSimon Glass 	vga_info->device = PCI_DEV(pcidev);
5274c59f953SSimon Glass 	vga_info->bus = PCI_BUS(pcidev);
5287282672dSSimon Glass #endif
5294c59f953SSimon Glass 	vga_info->pcidev = pcidev;
5304c59f953SSimon Glass 	vga_info->BIOSImage = copy_of_bios;
5314c59f953SSimon Glass 	vga_info->BIOSImageLen = bios_image_len;
532ece92f85SJason Jin 
533ece92f85SJason Jin 	/*Now execute the BIOS POST for the device*/
5344c59f953SSimon Glass 	if (copy_of_bios[0] != 0x55 || copy_of_bios[1] != 0xAA) {
535ece92f85SJason Jin 		printf("videoboot: Video ROM image is invalid!\n");
536ece92f85SJason Jin 		return false;
537ece92f85SJason Jin 	}
538ece92f85SJason Jin 
5394c59f953SSimon Glass 	PCI_doBIOSPOST(pcidev, vga_info, vesa_mode, mode_info);
540ece92f85SJason Jin 
541ece92f85SJason Jin 	/*Reset the size of the BIOS image to the final size*/
5424c59f953SSimon Glass 	vga_info->BIOSImageLen = copy_of_bios[2] * 512;
543ece92f85SJason Jin 	return true;
544ece92f85SJason Jin }
545ece92f85SJason Jin 
5467282672dSSimon Glass #ifdef CONFIG_DM_PCI
biosemu_setup(struct udevice * pcidev,BE_VGAInfo ** vga_infop)5477282672dSSimon Glass int biosemu_setup(struct udevice *pcidev, BE_VGAInfo **vga_infop)
5487282672dSSimon Glass #else
5494c59f953SSimon Glass int biosemu_setup(pci_dev_t pcidev, BE_VGAInfo **vga_infop)
5507282672dSSimon Glass #endif
5514c59f953SSimon Glass {
5524c59f953SSimon Glass 	BE_VGAInfo *VGAInfo;
5537282672dSSimon Glass #ifdef CONFIG_DM_PCI
5547282672dSSimon Glass 	pci_dev_t bdf = dm_pci_get_bdf(pcidev);
5554c59f953SSimon Glass 
5564c59f953SSimon Glass 	printf("videoboot: Booting PCI video card bus %d, function %d, device %d\n",
5577282672dSSimon Glass 	       PCI_BUS(bdf), PCI_FUNC(bdf), PCI_DEV(bdf));
5587282672dSSimon Glass #else
5597282672dSSimon Glass 	printf("videoboot: Booting PCI video card bus %d, function %d, device %d\n",
5604c59f953SSimon Glass 	       PCI_BUS(pcidev), PCI_FUNC(pcidev), PCI_DEV(pcidev));
5617282672dSSimon Glass #endif
5624c59f953SSimon Glass 	/*Initialise the x86 BIOS emulator*/
5634c59f953SSimon Glass 	if ((VGAInfo = malloc(sizeof(*VGAInfo))) == NULL) {
5644c59f953SSimon Glass 		printf("videoboot: Out of memory!\n");
5654c59f953SSimon Glass 		return -ENOMEM;
5664c59f953SSimon Glass 	}
5674c59f953SSimon Glass 	memset(VGAInfo, 0, sizeof(*VGAInfo));
5684c59f953SSimon Glass 	BE_init(0, 65536, VGAInfo, 0);
5694c59f953SSimon Glass 	*vga_infop = VGAInfo;
5704c59f953SSimon Glass 
5714c59f953SSimon Glass 	return 0;
5724c59f953SSimon Glass }
5734c59f953SSimon Glass 
biosemu_set_interrupt_handler(int intnum,int (* int_func)(void))5744c59f953SSimon Glass void biosemu_set_interrupt_handler(int intnum, int (*int_func)(void))
5754c59f953SSimon Glass {
5764c59f953SSimon Glass 	X86EMU_setupIntrFunc(intnum, (X86EMU_intrFuncs)int_func);
5774c59f953SSimon Glass }
5784c59f953SSimon Glass 
5797282672dSSimon Glass #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)5807282672dSSimon Glass int biosemu_run(struct udevice *pcidev, uchar *bios_rom, int bios_len,
5817282672dSSimon Glass 		BE_VGAInfo *vga_info, int clean_up, int vesa_mode,
5827282672dSSimon Glass 		struct vbe_mode_info *mode_info)
5837282672dSSimon Glass #else
5844c59f953SSimon Glass int biosemu_run(pci_dev_t pcidev, uchar *bios_rom, int bios_len,
5854c59f953SSimon Glass 		BE_VGAInfo *vga_info, int clean_up, int vesa_mode,
5864c59f953SSimon Glass 		struct vbe_mode_info *mode_info)
5877282672dSSimon Glass #endif
5884c59f953SSimon Glass {
5894c59f953SSimon Glass 	/*Post all the display controller BIOS'es*/
5904c59f953SSimon Glass 	if (!PCI_postController(pcidev, bios_rom, bios_len, vga_info,
5914c59f953SSimon Glass 				vesa_mode, mode_info))
5924c59f953SSimon Glass 		return -EINVAL;
5934c59f953SSimon Glass 
5944c59f953SSimon Glass 	/*
5954c59f953SSimon Glass 	 * Cleanup and exit the emulator if requested. If the BIOS emulator
5964c59f953SSimon Glass 	 * is needed after booting the card, we will not call BE_exit and
5974c59f953SSimon Glass 	 * leave it enabled for further use (ie: VESA driver etc).
5984c59f953SSimon Glass 	*/
5994c59f953SSimon Glass 	if (clean_up) {
6004c59f953SSimon Glass 		BE_exit();
6016e7b5f22SBin Meng 		if (vga_info->BIOSImage &&
602*2cd11a23SSimon Glass 		    (ulong)(vga_info->BIOSImage) != 0xc0000)
6034c59f953SSimon Glass 			free(vga_info->BIOSImage);
6044c59f953SSimon Glass 		free(vga_info);
6054c59f953SSimon Glass 		vga_info = NULL;
6064c59f953SSimon Glass 	}
6074c59f953SSimon Glass 
6084c59f953SSimon Glass 	return 0;
6094c59f953SSimon Glass }
6104c59f953SSimon Glass 
611ece92f85SJason Jin /****************************************************************************
612ece92f85SJason Jin PARAMETERS:
613ece92f85SJason Jin pcidev	    - PCI device info for the video card on the bus to boot
614ece92f85SJason Jin pVGAInfo    - Place to return VGA info structure is requested
615472d5460SYork Sun cleanUp	    - true to clean up on exit, false to leave emulator active
616ece92f85SJason Jin 
617ece92f85SJason Jin REMARKS:
618ece92f85SJason Jin Boots the PCI/AGP video card on the bus using the Video ROM BIOS image
619ece92f85SJason Jin and the X86 BIOS emulator module.
620ece92f85SJason Jin ****************************************************************************/
6217282672dSSimon Glass #ifdef CONFIG_DM_PCI
BootVideoCardBIOS(struct udevice * pcidev,BE_VGAInfo ** pVGAInfo,int clean_up)6227282672dSSimon Glass int BootVideoCardBIOS(struct udevice *pcidev, BE_VGAInfo **pVGAInfo,
6237282672dSSimon Glass 		      int clean_up)
6247282672dSSimon Glass #else
6254c59f953SSimon Glass int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo **pVGAInfo, int clean_up)
6267282672dSSimon Glass #endif
627ece92f85SJason Jin {
628ece92f85SJason Jin 	BE_VGAInfo *VGAInfo;
6294c59f953SSimon Glass 	int ret;
630ece92f85SJason Jin 
6314c59f953SSimon Glass 	ret = biosemu_setup(pcidev, &VGAInfo);
6324c59f953SSimon Glass 	if (ret)
633ece92f85SJason Jin 		return false;
6344c59f953SSimon Glass 	ret = biosemu_run(pcidev, NULL, 0, VGAInfo, clean_up, -1, NULL);
6354c59f953SSimon Glass 	if (ret)
6369624f6d9SEd Swarthout 		return false;
637ece92f85SJason Jin 
638ece92f85SJason Jin 	/* Return VGA info pointer if the caller requested it*/
639ece92f85SJason Jin 	if (pVGAInfo)
640ece92f85SJason Jin 		*pVGAInfo = VGAInfo;
6414c59f953SSimon Glass 
642ece92f85SJason Jin 	return true;
643ece92f85SJason Jin }
644