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 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 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 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 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 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 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 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 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 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 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 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 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 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 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