]> git.sur5r.net Git - u-boot/blobdiff - drivers/bios_emulator/atibios.c
rockchip: gpio: Read the GPIO value correctly
[u-boot] / drivers / bios_emulator / atibios.c
index 084339c1b29af6c3b2f1c615aa307c7983414c13..dec6230ad5cd6ca835a4d0f8b8c07906da74fa3f 100644 (file)
@@ -1,9 +1,9 @@
 /****************************************************************************
 *
-*                    Video BOOT Graphics Card POST Module
+*                   Video BOOT Graphics Card POST Module
 *
 *  ========================================================================
-*   Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+*   Copyright (C) 2007 Freescale Semiconductor, Inc.
 *   Jason Jin <Jason.jin@freescale.com>
 *
 *   Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
 *
 *  ========================================================================
 *
-* Language:     ANSI C
-* Environment:  Linux Kernel
-* Developer:    Kendall Bennett
+* Language:    ANSI C
+* Environment: Linux Kernel
+* Developer:   Kendall Bennett
 *
-* Description:  Module to implement booting PCI/AGP controllers on the
-*               bus. We use the x86 real mode emulator to run the BIOS on
-*               graphics controllers to bring the cards up.
+* Description: Module to implement booting PCI/AGP controllers on the
+*              bus. We use the x86 real mode emulator to run the BIOS on
+*              graphics controllers to bring the cards up.
 *
-*               Note that at present this module does *not* support
-*               multiple controllers.
+*              Note that at present this module does *not* support
+*              multiple controllers.
 *
-*               The orignal name of this file is warmboot.c.
-*               Jason ported this file to u-boot to run the ATI video card
-*               BIOS in u-boot.
+*              The orignal name of this file is warmboot.c.
+*              Jason ported this file to u-boot to run the ATI video card
+*              BIOS in u-boot.
 ****************************************************************************/
 #include <common.h>
-
-#ifdef CONFIG_BIOSEMU
-
-#include "biosemui.h"
+#include <bios_emul.h>
+#include <errno.h>
 #include <malloc.h>
+#include <vbe.h>
+#include "biosemui.h"
 
 /* Length of the BIOS image */
-#define MAX_BIOSLEN         (128 * 1024L)
-
-/* Define some useful types and macros */
-#define true                1
-#define false               0
+#define MAX_BIOSLEN        (128 * 1024L)
 
 /* Place to save PCI BAR's that we change and later restore */
 static u32 saveROMBaseAddress;
@@ -66,17 +62,172 @@ static u32 saveBaseAddress14;
 static u32 saveBaseAddress18;
 static u32 saveBaseAddress20;
 
+/* Addres im memory of VBE region */
+const int vbe_offset = 0x2000;
+
+static const void *bios_ptr(const void *buf, BE_VGAInfo *vga_info,
+                           u32 x86_dword_ptr)
+{
+       u32 seg_ofs, flat;
+
+       seg_ofs = le32_to_cpu(x86_dword_ptr);
+       flat = ((seg_ofs & 0xffff0000) >> 12) | (seg_ofs & 0xffff);
+       if (flat >= 0xc0000)
+               return vga_info->BIOSImage + flat - 0xc0000;
+       else
+               return buf + (flat - vbe_offset);
+}
+
+static int atibios_debug_mode(BE_VGAInfo *vga_info, RMREGS *regs,
+                             int vesa_mode, struct vbe_mode_info *mode_info)
+{
+       void *buffer = (void *)(M.mem_base + vbe_offset);
+       u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
+       u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
+       struct vesa_mode_info *vm;
+       struct vbe_info *info;
+       const u16 *modes_bios, *ptr;
+       u16 *modes;
+       int size;
+
+       debug("VBE: Getting information\n");
+       regs->e.eax = VESA_GET_INFO;
+       regs->e.esi = buffer_seg;
+       regs->e.edi = buffer_adr;
+       info = buffer;
+       memset(info, '\0', sizeof(*info));
+       strcpy(info->signature, "VBE2");
+       BE_int86(0x10, regs, regs);
+       if (regs->e.eax != 0x4f) {
+               debug("VESA_GET_INFO: error %x\n", regs->e.eax);
+               return -ENOSYS;
+       }
+       debug("version %x\n", le16_to_cpu(info->version));
+       debug("oem '%s'\n", (char *)bios_ptr(buffer, vga_info,
+                                            info->oem_string_ptr));
+       debug("vendor '%s'\n", (char *)bios_ptr(buffer, vga_info,
+                                               info->vendor_name_ptr));
+       debug("product '%s'\n", (char *)bios_ptr(buffer, vga_info,
+                                                info->product_name_ptr));
+       debug("rev '%s'\n", (char *)bios_ptr(buffer, vga_info,
+                                            info->product_rev_ptr));
+       modes_bios = bios_ptr(buffer, vga_info, info->modes_ptr);
+       debug("Modes: ");
+       for (ptr = modes_bios; *ptr != 0xffff; ptr++)
+               debug("%x ", le16_to_cpu(*ptr));
+       debug("\nmemory %dMB\n", le16_to_cpu(info->total_memory) >> 4);
+       size = (ptr - modes_bios) * sizeof(u16) + 2;
+       modes = malloc(size);
+       if (!modes)
+               return -ENOMEM;
+       memcpy(modes, modes_bios, size);
+
+       regs->e.eax = VESA_GET_CUR_MODE;
+       BE_int86(0x10, regs, regs);
+       if (regs->e.eax != 0x4f) {
+               debug("VESA_GET_CUR_MODE: error %x\n", regs->e.eax);
+               return -ENOSYS;
+       }
+       debug("Current mode %x\n", regs->e.ebx);
+
+       for (ptr = modes; *ptr != 0xffff; ptr++) {
+               int mode = le16_to_cpu(*ptr);
+               bool linear_ok;
+               int attr;
+
+               break;
+               debug("Mode %x: ", mode);
+               memset(buffer, '\0', sizeof(struct vbe_mode_info));
+               regs->e.eax = VESA_GET_MODE_INFO;
+               regs->e.ebx = 0;
+               regs->e.ecx = mode;
+               regs->e.edx = 0;
+               regs->e.esi = buffer_seg;
+               regs->e.edi = buffer_adr;
+               BE_int86(0x10, regs, regs);
+               if (regs->e.eax != 0x4f) {
+                       debug("VESA_GET_MODE_INFO: error %x\n", regs->e.eax);
+                       continue;
+               }
+               memcpy(mode_info->mode_info_block, buffer,
+                      sizeof(struct vesa_mode_info));
+               mode_info->valid = true;
+               vm = &mode_info->vesa;
+               attr = le16_to_cpu(vm->mode_attributes);
+               linear_ok = attr & 0x80;
+               debug("res %d x %d, %d bpp, mm %d, (Linear %s, attr %02x)\n",
+                     le16_to_cpu(vm->x_resolution),
+                     le16_to_cpu(vm->y_resolution),
+                     vm->bits_per_pixel, vm->memory_model,
+                     linear_ok ? "OK" : "not available",
+                     attr);
+               debug("\tRGB pos=%d,%d,%d, size=%d,%d,%d\n",
+                     vm->red_mask_pos, vm->green_mask_pos, vm->blue_mask_pos,
+                     vm->red_mask_size, vm->green_mask_size,
+                     vm->blue_mask_size);
+       }
+
+       return 0;
+}
+
+static int atibios_set_vesa_mode(RMREGS *regs, int vesa_mode,
+                                struct vbe_mode_info *mode_info)
+{
+       void *buffer = (void *)(M.mem_base + vbe_offset);
+       u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
+       u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
+       struct vesa_mode_info *vm;
+
+       debug("VBE: Setting VESA mode %#04x\n", vesa_mode);
+       regs->e.eax = VESA_SET_MODE;
+       regs->e.ebx = vesa_mode;
+       /* request linear framebuffer mode and don't clear display */
+       regs->e.ebx |= (1 << 14) | (1 << 15);
+       BE_int86(0x10, regs, regs);
+       if (regs->e.eax != 0x4f) {
+               debug("VESA_SET_MODE: error %x\n", regs->e.eax);
+               return -ENOSYS;
+       }
+
+       memset(buffer, '\0', sizeof(struct vbe_mode_info));
+       debug("VBE: Geting info for VESA mode %#04x\n", vesa_mode);
+       regs->e.eax = VESA_GET_MODE_INFO;
+       regs->e.ecx = vesa_mode;
+       regs->e.esi = buffer_seg;
+       regs->e.edi = buffer_adr;
+       BE_int86(0x10, regs, regs);
+       if (regs->e.eax != 0x4f) {
+               debug("VESA_GET_MODE_INFO: error %x\n", regs->e.eax);
+               return -ENOSYS;
+       }
+
+       memcpy(mode_info->mode_info_block, buffer,
+               sizeof(struct vesa_mode_info));
+       mode_info->valid = true;
+       mode_info->video_mode = vesa_mode;
+       vm = &mode_info->vesa;
+       vm->x_resolution = le16_to_cpu(vm->x_resolution);
+       vm->y_resolution = le16_to_cpu(vm->y_resolution);
+       vm->bytes_per_scanline = le16_to_cpu(vm->bytes_per_scanline);
+       vm->phys_base_ptr = le32_to_cpu(vm->phys_base_ptr);
+       vm->mode_attributes = le16_to_cpu(vm->mode_attributes);
+       debug("VBE: Init complete\n");
+
+       return 0;
+}
+
 /****************************************************************************
 PARAMETERS:
-pcidev  - PCI device info for the video card on the bus to boot
-VGAInfo - BIOS emulator VGA info structure
+pcidev - PCI device info for the video card on the bus to boot
+vga_info - BIOS emulator VGA info structure
 
 REMARKS:
 This function executes the BIOS POST code on the controller. We assume that
 at this stage the controller has its I/O and memory space enabled and
 that all other controllers are in a disabled state.
 ****************************************************************************/
-static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo * VGAInfo)
+static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo *vga_info,
+                          int vesa_mode, struct vbe_mode_info *mode_info)
 {
        RMREGS regs;
        RMSREGS sregs;
@@ -91,19 +242,25 @@ static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo * VGAInfo)
            ((int)PCI_DEV(pcidev) << 3) | (int)PCI_FUNC(pcidev);
 
        /*Setup the X86 emulator for the VGA BIOS*/
-       BE_setVGA(VGAInfo);
+       BE_setVGA(vga_info);
 
        /*Execute the BIOS POST code*/
        BE_callRealMode(0xC000, 0x0003, &regs, &sregs);
 
        /*Cleanup and exit*/
-       BE_getVGA(VGAInfo);
+       BE_getVGA(vga_info);
+
+       /* Useful for debugging */
+       if (0)
+               atibios_debug_mode(vga_info, &regs, vesa_mode, mode_info);
+       if (vesa_mode != -1)
+               atibios_set_vesa_mode(&regs, vesa_mode, mode_info);
 }
 
 /****************************************************************************
 PARAMETERS:
-pcidev  - PCI device info for the video card on the bus
-bar     - Place to return the base address register offset to use
+pcidev - PCI device info for the video card on the bus
+bar    - Place to return the base address register offset to use
 
 RETURNS:
 The address to use to map the secondary BIOS (AGP devices)
@@ -166,7 +323,7 @@ static void PCI_fixupIObase(pci_dev_t pcidev, int reg, u32 * base)
 
 /****************************************************************************
 PARAMETERS:
-pcidev  - PCI device info for the video card on the bus
+pcidev - PCI device info for the video card on the bus
 
 RETURNS:
 Pointers to the mapped BIOS image
@@ -176,7 +333,7 @@ Maps a pointer to the BIOS image on the graphics card on the PCI bus.
 ****************************************************************************/
 void *PCI_mapBIOSImage(pci_dev_t pcidev)
 {
-       u32 BIOSImagePhys;
+       u32 BIOSImageBus;
        int BIOSImageBAR;
        u8 *BIOSImage;
 
@@ -196,18 +353,20 @@ void *PCI_mapBIOSImage(pci_dev_t pcidev)
        /* Some cards have problems that stop us from being able to read the
         BIOS image from the ROM BAR. To fix this we have to do some chipset
         specific programming for different cards to solve this problem.
-        */
+       */
 
-       if ((BIOSImagePhys = PCI_findBIOSAddr(pcidev, &BIOSImageBAR)) == 0) {
+       BIOSImageBus = PCI_findBIOSAddr(pcidev, &BIOSImageBAR);
+       if (BIOSImageBus == 0) {
                printf("Find bios addr error\n");
                return NULL;
        }
 
-       BIOSImage = (u8 *) BIOSImagePhys;
+       BIOSImage = pci_bus_to_virt(pcidev, BIOSImageBus,
+                                   PCI_REGION_MEM, 0, MAP_NOCACHE);
 
        /*Change the PCI BAR registers to map it onto the bus.*/
        pci_write_config_dword(pcidev, BIOSImageBAR, 0);
-       pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, BIOSImagePhys | 0x1);
+       pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, BIOSImageBus | 0x1);
 
        udelay(1);
 
@@ -223,7 +382,7 @@ void *PCI_mapBIOSImage(pci_dev_t pcidev)
 
 /****************************************************************************
 PARAMETERS:
-pcidev  - PCI device info for the video card on the bus
+pcidev - PCI device info for the video card on the bus
 
 REMARKS:
 Unmaps the BIOS image for the device and restores framebuffer mappings
@@ -239,70 +398,71 @@ void PCI_unmapBIOSImage(pci_dev_t pcidev, void *BIOSImage)
 
 /****************************************************************************
 PARAMETERS:
-pcidev  - PCI device info for the video card on the bus to boot
+pcidev - PCI device info for the video card on the bus to boot
 VGAInfo - BIOS emulator VGA info structure
 
 RETURNS:
-True if successfully initialised, false if not.
+true if successfully initialised, false if not.
 
 REMARKS:
 Loads and POST's the display controllers BIOS, directly from the BIOS
 image we can extract over the PCI bus.
 ****************************************************************************/
-static int PCI_postController(pci_dev_t pcidev, BE_VGAInfo * VGAInfo)
+static int PCI_postController(pci_dev_t pcidev, uchar *bios_rom, int bios_len,
+                             BE_VGAInfo *vga_info, int vesa_mode,
+                             struct vbe_mode_info *mode_info)
 {
-       u32 BIOSImageLen;
-       uchar *mappedBIOS;
-       uchar *copyOfBIOS;
-
-       /*Allocate memory to store copy of BIOS from display controller*/
-       if ((mappedBIOS = PCI_mapBIOSImage(pcidev)) == NULL) {
-               printf("videoboot: Video ROM failed to map!\n");
-               return false;
-       }
+       u32 bios_image_len;
+       uchar *mapped_bios;
+       uchar *copy_of_bios;
+
+       if (bios_rom) {
+               copy_of_bios = bios_rom;
+               bios_image_len = bios_len;
+       } else {
+               /*
+                * Allocate memory to store copy of BIOS from display
+                * controller
+                */
+               mapped_bios = PCI_mapBIOSImage(pcidev);
+               if (mapped_bios == NULL) {
+                       printf("videoboot: Video ROM failed to map!\n");
+                       return false;
+               }
 
-       BIOSImageLen = mappedBIOS[2] * 512;
+               bios_image_len = mapped_bios[2] * 512;
 
-       if ((copyOfBIOS = malloc(BIOSImageLen)) == NULL) {
-               printf("videoboot: Out of memory!\n");
-               return false;
+               copy_of_bios = malloc(bios_image_len);
+               if (copy_of_bios == NULL) {
+                       printf("videoboot: Out of memory!\n");
+                       return false;
+               }
+               memcpy(copy_of_bios, mapped_bios, bios_image_len);
+               PCI_unmapBIOSImage(pcidev, mapped_bios);
        }
-       memcpy(copyOfBIOS, mappedBIOS, BIOSImageLen);
 
-       PCI_unmapBIOSImage(pcidev, mappedBIOS);
-
-       /*Save information in VGAInfo structure*/
-       VGAInfo->function = PCI_FUNC(pcidev);
-       VGAInfo->device = PCI_DEV(pcidev);
-       VGAInfo->bus = PCI_BUS(pcidev);
-       VGAInfo->pcidev = pcidev;
-       VGAInfo->BIOSImage = copyOfBIOS;
-       VGAInfo->BIOSImageLen = BIOSImageLen;
+       /*Save information in vga_info structure*/
+       vga_info->function = PCI_FUNC(pcidev);
+       vga_info->device = PCI_DEV(pcidev);
+       vga_info->bus = PCI_BUS(pcidev);
+       vga_info->pcidev = pcidev;
+       vga_info->BIOSImage = copy_of_bios;
+       vga_info->BIOSImageLen = bios_image_len;
 
        /*Now execute the BIOS POST for the device*/
-       if (copyOfBIOS[0] != 0x55 || copyOfBIOS[1] != 0xAA) {
+       if (copy_of_bios[0] != 0x55 || copy_of_bios[1] != 0xAA) {
                printf("videoboot: Video ROM image is invalid!\n");
                return false;
        }
 
-       PCI_doBIOSPOST(pcidev, VGAInfo);
+       PCI_doBIOSPOST(pcidev, vga_info, vesa_mode, mode_info);
 
        /*Reset the size of the BIOS image to the final size*/
-       VGAInfo->BIOSImageLen = copyOfBIOS[2] * 512;
+       vga_info->BIOSImageLen = copy_of_bios[2] * 512;
        return true;
 }
 
-/****************************************************************************
-PARAMETERS:
-pcidev      - PCI device info for the video card on the bus to boot
-pVGAInfo    - Place to return VGA info structure is requested
-cleanUp     - True to clean up on exit, false to leave emulator active
-
-REMARKS:
-Boots the PCI/AGP video card on the bus using the Video ROM BIOS image
-and the X86 BIOS emulator module.
-****************************************************************************/
-int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp)
+int biosemu_setup(pci_dev_t pcidev, BE_VGAInfo **vga_infop)
 {
        BE_VGAInfo *VGAInfo;
 
@@ -312,29 +472,71 @@ int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp)
        /*Initialise the x86 BIOS emulator*/
        if ((VGAInfo = malloc(sizeof(*VGAInfo))) == NULL) {
                printf("videoboot: Out of memory!\n");
-               return false;
+               return -ENOMEM;
        }
        memset(VGAInfo, 0, sizeof(*VGAInfo));
        BE_init(0, 65536, VGAInfo, 0);
+       *vga_infop = VGAInfo;
 
-       /*Post all the display controller BIOS'es*/
-       PCI_postController(pcidev, VGAInfo);
+       return 0;
+}
 
-       /*Cleanup and exit the emulator if requested. If the BIOS emulator
-       is needed after booting the card, we will not call BE_exit and
-       leave it enabled for further use (ie: VESA driver etc).
+void biosemu_set_interrupt_handler(int intnum, int (*int_func)(void))
+{
+       X86EMU_setupIntrFunc(intnum, (X86EMU_intrFuncs)int_func);
+}
+
+int biosemu_run(pci_dev_t pcidev, uchar *bios_rom, int bios_len,
+               BE_VGAInfo *vga_info, int clean_up, int vesa_mode,
+               struct vbe_mode_info *mode_info)
+{
+       /*Post all the display controller BIOS'es*/
+       if (!PCI_postController(pcidev, bios_rom, bios_len, vga_info,
+                               vesa_mode, mode_info))
+               return -EINVAL;
+
+       /*
+        * Cleanup and exit the emulator if requested. If the BIOS emulator
+        * is needed after booting the card, we will not call BE_exit and
+        * leave it enabled for further use (ie: VESA driver etc).
        */
-       if (cleanUp) {
+       if (clean_up) {
                BE_exit();
-               if (VGAInfo->BIOSImage)
-                       free(VGAInfo->BIOSImage);
-               free(VGAInfo);
-               VGAInfo = NULL;
+               if (vga_info->BIOSImage &&
+                   (u32)(vga_info->BIOSImage) != 0xc0000)
+                       free(vga_info->BIOSImage);
+               free(vga_info);
+               vga_info = NULL;
        }
-       /*Return VGA info pointer if the caller requested it*/
+
+       return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+pcidev     - PCI device info for the video card on the bus to boot
+pVGAInfo    - Place to return VGA info structure is requested
+cleanUp            - true to clean up on exit, false to leave emulator active
+
+REMARKS:
+Boots the PCI/AGP video card on the bus using the Video ROM BIOS image
+and the X86 BIOS emulator module.
+****************************************************************************/
+int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo **pVGAInfo, int clean_up)
+{
+       BE_VGAInfo *VGAInfo;
+       int ret;
+
+       ret = biosemu_setup(pcidev, &VGAInfo);
+       if (ret)
+               return false;
+       ret = biosemu_run(pcidev, NULL, 0, VGAInfo, clean_up, -1, NULL);
+       if (ret)
+               return false;
+
+       /* Return VGA info pointer if the caller requested it*/
        if (pVGAInfo)
                *pVGAInfo = VGAInfo;
+
        return true;
 }
-
-#endif