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(®s, 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, ®s, &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, ®s, vesa_mode, mode_info);
269*4882a593Smuzhiyun if (vesa_mode != -1)
270*4882a593Smuzhiyun atibios_set_vesa_mode(®s, 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