blob: d7ff3e9f82dca9b08bbf3ff0cd6a0a85284536dc [file] [log] [blame]
Gerd Hoffmannedf4fe52019-10-23 07:50:37 +02001// Simple framebuffer vgabios for use with qemu bochs-display device
2//
3// Copyright (C) 2019 Gerd Hoffmann <kraxel@redhat.com>
4//
5// This file may be distributed under the terms of the GNU LGPLv3 license.
6
Gerd Hoffmann77404b42017-11-15 14:43:10 +01007#include "biosvar.h" // GET_BDA
8#include "output.h" // dprintf
9#include "string.h" // memset16_far
10#include "bochsvga.h" // VBE_BOCHS_*
11#include "hw/pci.h" // pci_config_readl
12#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0
Gerd Hoffmann2f87fe32019-03-19 11:48:04 +010013#include "vgabios.h" // SET_VGA
Gerd Hoffmann77404b42017-11-15 14:43:10 +010014#include "vgautil.h" // VBE_total_memory
15
16#define FRAMEBUFFER_WIDTH 1024
17#define FRAMEBUFFER_HEIGHT 768
18#define FRAMEBUFFER_BPP 4
Gerd Hoffmann77404b42017-11-15 14:43:10 +010019
20int
21bochs_display_setup(void)
22{
23 dprintf(1, "bochs-display: setup called\n");
24
25 if (GET_GLOBAL(HaveRunInit))
26 return 0;
27
28 int bdf = GET_GLOBAL(VgaBDF);
29 if (bdf == 0)
30 return 0;
31
32 u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
33 u32 lfb_addr = bar & PCI_BASE_ADDRESS_MEM_MASK;
34 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_2);
35 u32 io_addr = bar & PCI_BASE_ADDRESS_IO_MASK;
36 dprintf(1, "bochs-display: bdf %02x:%02x.%x, bar 0 at 0x%x, bar 1 at 0x%x\n"
37 , pci_bdf_to_bus(bdf) , pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf),
38 lfb_addr, io_addr);
39
40 u16 *dispi = (void*)(io_addr + 0x500);
41 u8 *vga = (void*)(io_addr + 0x400);
42 u16 id = readw(dispi + VBE_DISPI_INDEX_ID);
43 dprintf(1, "bochs-display: id is 0x%x, %s\n", id
44 , id == VBE_DISPI_ID5 ? "good" : "FAIL");
45 if (id != VBE_DISPI_ID5)
Gerd Hoffmann7bf9fff2018-06-15 08:18:45 +020046 return -1;
Gerd Hoffmann77404b42017-11-15 14:43:10 +010047
Gerd Hoffmann2f87fe32019-03-19 11:48:04 +010048 int i;
49 u8 *edid = (void*)(io_addr);
50 for (i = 0; i < sizeof(VBE_edid); i++)
51 SET_VGA(VBE_edid[i], readb(edid + i));
52
Gerd Hoffmanna3fd63c2019-03-19 12:20:52 +010053 int fb_width = FRAMEBUFFER_WIDTH;
54 int fb_height = FRAMEBUFFER_HEIGHT;
55 if (GET_GLOBAL(VBE_edid[0]) == 0x00 &&
56 GET_GLOBAL(VBE_edid[1]) == 0xff) {
57 fb_width = GET_GLOBAL(VBE_edid[54 + 2]);
58 fb_width |= (GET_GLOBAL(VBE_edid[54 + 4]) & 0xf0) << 4;
59 fb_height = GET_GLOBAL(VBE_edid[54 + 5]);
60 fb_height |= (GET_GLOBAL(VBE_edid[54 + 7]) & 0xf0) << 4;
61 }
62 int fb_stride = FRAMEBUFFER_BPP * fb_width;
63
Gerd Hoffmann2f87fe32019-03-19 11:48:04 +010064 dprintf(1, "bochs-display: using %dx%d, %d bpp (%d stride)\n"
Gerd Hoffmanna3fd63c2019-03-19 12:20:52 +010065 , fb_width, fb_height
66 , FRAMEBUFFER_BPP * 8, fb_stride);
Gerd Hoffmann77404b42017-11-15 14:43:10 +010067
68 cbvga_setup_modes(lfb_addr, FRAMEBUFFER_BPP * 8,
Gerd Hoffmanna3fd63c2019-03-19 12:20:52 +010069 fb_width, fb_height, fb_stride);
Gerd Hoffmann77404b42017-11-15 14:43:10 +010070
Gerd Hoffmanna3fd63c2019-03-19 12:20:52 +010071 writew(dispi + VBE_DISPI_INDEX_XRES, fb_width);
72 writew(dispi + VBE_DISPI_INDEX_YRES, fb_height);
Gerd Hoffmann77404b42017-11-15 14:43:10 +010073 writew(dispi + VBE_DISPI_INDEX_BPP, FRAMEBUFFER_BPP * 8);
74 writew(dispi + VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED);
75
76 writeb(vga, 0x20); /* unblank (for qemu -device VGA) */
77
78 return 0;
79}