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