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