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