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(®s, 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, ®s, &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, ®s, vesa_mode, mode_info);
2694c59f953SSimon Glass if (vesa_mode != -1)
2704c59f953SSimon Glass atibios_set_vesa_mode(®s, 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