xref: /rk3399_rockchip-uboot/drivers/bios_emulator/atibios.c (revision 4c2e3da82dc2b7f8b39b7f1d57f570e4bc5caa6d)
1ece92f85SJason Jin /****************************************************************************
2ece92f85SJason Jin *
3ece92f85SJason Jin *		     Video BOOT Graphics Card POST Module
4ece92f85SJason Jin *
5ece92f85SJason Jin *  ========================================================================
6*4c2e3da8SKumar 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>
49ece92f85SJason Jin #include "biosemui.h"
50ece92f85SJason Jin #include <malloc.h>
51ece92f85SJason Jin 
52ece92f85SJason Jin /* Length of the BIOS image */
53ece92f85SJason Jin #define MAX_BIOSLEN	    (128 * 1024L)
54ece92f85SJason Jin 
55ece92f85SJason Jin /* Define some useful types and macros */
56ece92f85SJason Jin #define true		    1
57ece92f85SJason Jin #define false		    0
58ece92f85SJason Jin 
59ece92f85SJason Jin /* Place to save PCI BAR's that we change and later restore */
60ece92f85SJason Jin static u32 saveROMBaseAddress;
61ece92f85SJason Jin static u32 saveBaseAddress10;
62ece92f85SJason Jin static u32 saveBaseAddress14;
63ece92f85SJason Jin static u32 saveBaseAddress18;
64ece92f85SJason Jin static u32 saveBaseAddress20;
65ece92f85SJason Jin 
66ece92f85SJason Jin /****************************************************************************
67ece92f85SJason Jin PARAMETERS:
68ece92f85SJason Jin pcidev	- PCI device info for the video card on the bus to boot
69ece92f85SJason Jin VGAInfo - BIOS emulator VGA info structure
70ece92f85SJason Jin 
71ece92f85SJason Jin REMARKS:
72ece92f85SJason Jin This function executes the BIOS POST code on the controller. We assume that
73ece92f85SJason Jin at this stage the controller has its I/O and memory space enabled and
74ece92f85SJason Jin that all other controllers are in a disabled state.
75ece92f85SJason Jin ****************************************************************************/
76ece92f85SJason Jin static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo * VGAInfo)
77ece92f85SJason Jin {
78ece92f85SJason Jin 	RMREGS regs;
79ece92f85SJason Jin 	RMSREGS sregs;
80ece92f85SJason Jin 
81ece92f85SJason Jin 	/* Determine the value to store in AX for BIOS POST. Per the PCI specs,
82ece92f85SJason Jin 	 AH must contain the bus and AL must contain the devfn, encoded as
83ece92f85SJason Jin 	 (dev << 3) | fn
84ece92f85SJason Jin 	 */
85ece92f85SJason Jin 	memset(&regs, 0, sizeof(regs));
86ece92f85SJason Jin 	memset(&sregs, 0, sizeof(sregs));
87ece92f85SJason Jin 	regs.x.ax = ((int)PCI_BUS(pcidev) << 8) |
88ece92f85SJason Jin 	    ((int)PCI_DEV(pcidev) << 3) | (int)PCI_FUNC(pcidev);
89ece92f85SJason Jin 
90ece92f85SJason Jin 	/*Setup the X86 emulator for the VGA BIOS*/
91ece92f85SJason Jin 	BE_setVGA(VGAInfo);
92ece92f85SJason Jin 
93ece92f85SJason Jin 	/*Execute the BIOS POST code*/
94ece92f85SJason Jin 	BE_callRealMode(0xC000, 0x0003, &regs, &sregs);
95ece92f85SJason Jin 
96ece92f85SJason Jin 	/*Cleanup and exit*/
97ece92f85SJason Jin 	BE_getVGA(VGAInfo);
98ece92f85SJason Jin }
99ece92f85SJason Jin 
100ece92f85SJason Jin /****************************************************************************
101ece92f85SJason Jin PARAMETERS:
102ece92f85SJason Jin pcidev	- PCI device info for the video card on the bus
103ece92f85SJason Jin bar	- Place to return the base address register offset to use
104ece92f85SJason Jin 
105ece92f85SJason Jin RETURNS:
106ece92f85SJason Jin The address to use to map the secondary BIOS (AGP devices)
107ece92f85SJason Jin 
108ece92f85SJason Jin REMARKS:
109ece92f85SJason Jin Searches all the PCI base address registers for the device looking for a
110ece92f85SJason Jin memory mapping that is large enough to hold our ROM BIOS. We usually end up
111ece92f85SJason Jin finding the framebuffer mapping (usually BAR 0x10), and we use this mapping
112ece92f85SJason Jin to map the BIOS for the device into. We use a mapping that is already
113ece92f85SJason Jin assigned to the device to ensure the memory range will be passed through
114ece92f85SJason Jin by any PCI->PCI or AGP->PCI bridge that may be present.
115ece92f85SJason Jin 
116ece92f85SJason Jin NOTE: Usually this function is only used for AGP devices, but it may be
117ece92f85SJason Jin       used for PCI devices that have already been POST'ed and the BIOS
118ece92f85SJason Jin       ROM base address has been zero'ed out.
119ece92f85SJason Jin 
120ece92f85SJason Jin NOTE: This function leaves the original memory aperture disabled by leaving
121ece92f85SJason Jin       it programmed to all 1's. It must be restored to the correct value
122ece92f85SJason Jin       later.
123ece92f85SJason Jin ****************************************************************************/
124ece92f85SJason Jin static u32 PCI_findBIOSAddr(pci_dev_t pcidev, int *bar)
125ece92f85SJason Jin {
126ece92f85SJason Jin 	u32 base, size;
127ece92f85SJason Jin 
128ece92f85SJason Jin 	for (*bar = 0x10; *bar <= 0x14; (*bar) += 4) {
129ece92f85SJason Jin 		pci_read_config_dword(pcidev, *bar, &base);
130ece92f85SJason Jin 		if (!(base & 0x1)) {
131ece92f85SJason Jin 			pci_write_config_dword(pcidev, *bar, 0xFFFFFFFF);
132ece92f85SJason Jin 			pci_read_config_dword(pcidev, *bar, &size);
133ece92f85SJason Jin 			size = ~(size & ~0xFF) + 1;
134ece92f85SJason Jin 			if (size >= MAX_BIOSLEN)
135ece92f85SJason Jin 				return base & ~0xFF;
136ece92f85SJason Jin 		}
137ece92f85SJason Jin 	}
138ece92f85SJason Jin 	return 0;
139ece92f85SJason Jin }
140ece92f85SJason Jin 
141ece92f85SJason Jin /****************************************************************************
142ece92f85SJason Jin REMARKS:
143ece92f85SJason Jin Some non-x86 Linux kernels map PCI relocateable I/O to values that
144ece92f85SJason Jin are above 64K, which will not work with the BIOS image that requires
145ece92f85SJason Jin the offset for the I/O ports to be a maximum of 16-bits. Ideally
146ece92f85SJason Jin someone should fix the kernel to map the I/O ports for VGA compatible
147ece92f85SJason Jin devices to a different location (or just all I/O ports since it is
148ece92f85SJason Jin unlikely you can have enough devices in the machine to use up all
149ece92f85SJason Jin 64K of the I/O space - a total of more than 256 cards would be
150ece92f85SJason Jin necessary).
151ece92f85SJason Jin 
152ece92f85SJason Jin Anyway to fix this we change all I/O mapped base registers and
153ece92f85SJason Jin chop off the top bits.
154ece92f85SJason Jin ****************************************************************************/
155ece92f85SJason Jin static void PCI_fixupIObase(pci_dev_t pcidev, int reg, u32 * base)
156ece92f85SJason Jin {
157ece92f85SJason Jin 	if ((*base & 0x1) && (*base > 0xFFFE)) {
158ece92f85SJason Jin 		*base &= 0xFFFF;
159ece92f85SJason Jin 		pci_write_config_dword(pcidev, reg, *base);
160ece92f85SJason Jin 
161ece92f85SJason Jin 	}
162ece92f85SJason Jin }
163ece92f85SJason Jin 
164ece92f85SJason Jin /****************************************************************************
165ece92f85SJason Jin PARAMETERS:
166ece92f85SJason Jin pcidev	- PCI device info for the video card on the bus
167ece92f85SJason Jin 
168ece92f85SJason Jin RETURNS:
169ece92f85SJason Jin Pointers to the mapped BIOS image
170ece92f85SJason Jin 
171ece92f85SJason Jin REMARKS:
172ece92f85SJason Jin Maps a pointer to the BIOS image on the graphics card on the PCI bus.
173ece92f85SJason Jin ****************************************************************************/
174ece92f85SJason Jin void *PCI_mapBIOSImage(pci_dev_t pcidev)
175ece92f85SJason Jin {
176ece92f85SJason Jin 	u32 BIOSImagePhys;
177ece92f85SJason Jin 	int BIOSImageBAR;
178ece92f85SJason Jin 	u8 *BIOSImage;
179ece92f85SJason Jin 
180ece92f85SJason Jin 	/*Save PCI BAR registers that might get changed*/
181ece92f85SJason Jin 	pci_read_config_dword(pcidev, PCI_ROM_ADDRESS, &saveROMBaseAddress);
182ece92f85SJason Jin 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &saveBaseAddress10);
183ece92f85SJason Jin 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14);
184ece92f85SJason Jin 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_2, &saveBaseAddress18);
185ece92f85SJason Jin 	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20);
186ece92f85SJason Jin 
187ece92f85SJason Jin 	/*Fix up I/O base registers to less than 64K */
188ece92f85SJason Jin 	if(saveBaseAddress14 != 0)
189ece92f85SJason Jin 		PCI_fixupIObase(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14);
190ece92f85SJason Jin 	else
191ece92f85SJason Jin 		PCI_fixupIObase(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20);
192ece92f85SJason Jin 
193ece92f85SJason Jin 	/* Some cards have problems that stop us from being able to read the
194ece92f85SJason Jin 	 BIOS image from the ROM BAR. To fix this we have to do some chipset
195ece92f85SJason Jin 	 specific programming for different cards to solve this problem.
196ece92f85SJason Jin 	*/
197ece92f85SJason Jin 
198ece92f85SJason Jin 	if ((BIOSImagePhys = PCI_findBIOSAddr(pcidev, &BIOSImageBAR)) == 0) {
199ece92f85SJason Jin 		printf("Find bios addr error\n");
200ece92f85SJason Jin 		return NULL;
201ece92f85SJason Jin 	}
202ece92f85SJason Jin 
203ece92f85SJason Jin 	BIOSImage = (u8 *) BIOSImagePhys;
204ece92f85SJason Jin 
205ece92f85SJason Jin 	/*Change the PCI BAR registers to map it onto the bus.*/
206ece92f85SJason Jin 	pci_write_config_dword(pcidev, BIOSImageBAR, 0);
207ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, BIOSImagePhys | 0x1);
208ece92f85SJason Jin 
209ece92f85SJason Jin 	udelay(1);
210ece92f85SJason Jin 
211ece92f85SJason Jin 	/*Check that the BIOS image is valid. If not fail, or return the
212ece92f85SJason Jin 	 compiled in BIOS image if that option was enabled
213ece92f85SJason Jin 	 */
214ece92f85SJason Jin 	if (BIOSImage[0] != 0x55 || BIOSImage[1] != 0xAA || BIOSImage[2] == 0) {
215ece92f85SJason Jin 		return NULL;
216ece92f85SJason Jin 	}
217ece92f85SJason Jin 
218ece92f85SJason Jin 	return BIOSImage;
219ece92f85SJason Jin }
220ece92f85SJason Jin 
221ece92f85SJason Jin /****************************************************************************
222ece92f85SJason Jin PARAMETERS:
223ece92f85SJason Jin pcidev	- PCI device info for the video card on the bus
224ece92f85SJason Jin 
225ece92f85SJason Jin REMARKS:
226ece92f85SJason Jin Unmaps the BIOS image for the device and restores framebuffer mappings
227ece92f85SJason Jin ****************************************************************************/
228ece92f85SJason Jin void PCI_unmapBIOSImage(pci_dev_t pcidev, void *BIOSImage)
229ece92f85SJason Jin {
230ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, saveROMBaseAddress);
231ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_0, saveBaseAddress10);
232ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_1, saveBaseAddress14);
233ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_2, saveBaseAddress18);
234ece92f85SJason Jin 	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_4, saveBaseAddress20);
235ece92f85SJason Jin }
236ece92f85SJason Jin 
237ece92f85SJason Jin /****************************************************************************
238ece92f85SJason Jin PARAMETERS:
239ece92f85SJason Jin pcidev	- PCI device info for the video card on the bus to boot
240ece92f85SJason Jin VGAInfo - BIOS emulator VGA info structure
241ece92f85SJason Jin 
242ece92f85SJason Jin RETURNS:
243ece92f85SJason Jin True if successfully initialised, false if not.
244ece92f85SJason Jin 
245ece92f85SJason Jin REMARKS:
246ece92f85SJason Jin Loads and POST's the display controllers BIOS, directly from the BIOS
247ece92f85SJason Jin image we can extract over the PCI bus.
248ece92f85SJason Jin ****************************************************************************/
249ece92f85SJason Jin static int PCI_postController(pci_dev_t pcidev, BE_VGAInfo * VGAInfo)
250ece92f85SJason Jin {
251ece92f85SJason Jin 	u32 BIOSImageLen;
252ece92f85SJason Jin 	uchar *mappedBIOS;
253ece92f85SJason Jin 	uchar *copyOfBIOS;
254ece92f85SJason Jin 
255ece92f85SJason Jin 	/*Allocate memory to store copy of BIOS from display controller*/
256ece92f85SJason Jin 	if ((mappedBIOS = PCI_mapBIOSImage(pcidev)) == NULL) {
257ece92f85SJason Jin 		printf("videoboot: Video ROM failed to map!\n");
258ece92f85SJason Jin 		return false;
259ece92f85SJason Jin 	}
260ece92f85SJason Jin 
261ece92f85SJason Jin 	BIOSImageLen = mappedBIOS[2] * 512;
262ece92f85SJason Jin 
263ece92f85SJason Jin 	if ((copyOfBIOS = malloc(BIOSImageLen)) == NULL) {
264ece92f85SJason Jin 		printf("videoboot: Out of memory!\n");
265ece92f85SJason Jin 		return false;
266ece92f85SJason Jin 	}
267ece92f85SJason Jin 	memcpy(copyOfBIOS, mappedBIOS, BIOSImageLen);
268ece92f85SJason Jin 
269ece92f85SJason Jin 	PCI_unmapBIOSImage(pcidev, mappedBIOS);
270ece92f85SJason Jin 
271ece92f85SJason Jin 	/*Save information in VGAInfo structure*/
272ece92f85SJason Jin 	VGAInfo->function = PCI_FUNC(pcidev);
273ece92f85SJason Jin 	VGAInfo->device = PCI_DEV(pcidev);
274ece92f85SJason Jin 	VGAInfo->bus = PCI_BUS(pcidev);
275ece92f85SJason Jin 	VGAInfo->pcidev = pcidev;
276ece92f85SJason Jin 	VGAInfo->BIOSImage = copyOfBIOS;
277ece92f85SJason Jin 	VGAInfo->BIOSImageLen = BIOSImageLen;
278ece92f85SJason Jin 
279ece92f85SJason Jin 	/*Now execute the BIOS POST for the device*/
280ece92f85SJason Jin 	if (copyOfBIOS[0] != 0x55 || copyOfBIOS[1] != 0xAA) {
281ece92f85SJason Jin 		printf("videoboot: Video ROM image is invalid!\n");
282ece92f85SJason Jin 		return false;
283ece92f85SJason Jin 	}
284ece92f85SJason Jin 
285ece92f85SJason Jin 	PCI_doBIOSPOST(pcidev, VGAInfo);
286ece92f85SJason Jin 
287ece92f85SJason Jin 	/*Reset the size of the BIOS image to the final size*/
288ece92f85SJason Jin 	VGAInfo->BIOSImageLen = copyOfBIOS[2] * 512;
289ece92f85SJason Jin 	return true;
290ece92f85SJason Jin }
291ece92f85SJason Jin 
292ece92f85SJason Jin /****************************************************************************
293ece92f85SJason Jin PARAMETERS:
294ece92f85SJason Jin pcidev	    - PCI device info for the video card on the bus to boot
295ece92f85SJason Jin pVGAInfo    - Place to return VGA info structure is requested
296ece92f85SJason Jin cleanUp	    - True to clean up on exit, false to leave emulator active
297ece92f85SJason Jin 
298ece92f85SJason Jin REMARKS:
299ece92f85SJason Jin Boots the PCI/AGP video card on the bus using the Video ROM BIOS image
300ece92f85SJason Jin and the X86 BIOS emulator module.
301ece92f85SJason Jin ****************************************************************************/
302ece92f85SJason Jin int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp)
303ece92f85SJason Jin {
304ece92f85SJason Jin 	BE_VGAInfo *VGAInfo;
305ece92f85SJason Jin 
306ece92f85SJason Jin 	printf("videoboot: Booting PCI video card bus %d, function %d, device %d\n",
307ece92f85SJason Jin 	     PCI_BUS(pcidev), PCI_FUNC(pcidev), PCI_DEV(pcidev));
308ece92f85SJason Jin 
309ece92f85SJason Jin 	/*Initialise the x86 BIOS emulator*/
310ece92f85SJason Jin 	if ((VGAInfo = malloc(sizeof(*VGAInfo))) == NULL) {
311ece92f85SJason Jin 		printf("videoboot: Out of memory!\n");
312ece92f85SJason Jin 		return false;
313ece92f85SJason Jin 	}
314ece92f85SJason Jin 	memset(VGAInfo, 0, sizeof(*VGAInfo));
315ece92f85SJason Jin 	BE_init(0, 65536, VGAInfo, 0);
316ece92f85SJason Jin 
317ece92f85SJason Jin 	/*Post all the display controller BIOS'es*/
318ece92f85SJason Jin 	PCI_postController(pcidev, VGAInfo);
319ece92f85SJason Jin 
320ece92f85SJason Jin 	/*Cleanup and exit the emulator if requested. If the BIOS emulator
321ece92f85SJason Jin 	is needed after booting the card, we will not call BE_exit and
322ece92f85SJason Jin 	leave it enabled for further use (ie: VESA driver etc).
323ece92f85SJason Jin 	*/
324ece92f85SJason Jin 	if (cleanUp) {
325ece92f85SJason Jin 		BE_exit();
326ece92f85SJason Jin 		if (VGAInfo->BIOSImage)
327ece92f85SJason Jin 			free(VGAInfo->BIOSImage);
328ece92f85SJason Jin 		free(VGAInfo);
329ece92f85SJason Jin 		VGAInfo = NULL;
330ece92f85SJason Jin 	}
331ece92f85SJason Jin 	/*Return VGA info pointer if the caller requested it*/
332ece92f85SJason Jin 	if (pVGAInfo)
333ece92f85SJason Jin 		*pVGAInfo = VGAInfo;
334ece92f85SJason Jin 	return true;
335ece92f85SJason Jin }
336