1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <ddk/binding.h> 6#include <ddk/debug.h> 7#include <ddk/device.h> 8#include <ddk/driver.h> 9#include <ddk/protocol/pci.h> 10#include <zircon/pixelformat.h> 11#include <zircon/process.h> 12 13#include "simple-display.h" 14 15#define DISPLAY_WIDTH 1024 16#define DISPLAY_HEIGHT 768 17#define DISPLAY_FORMAT ZX_PIXEL_FORMAT_RGB_565 18 19#define QEMU_VGA_VID (0x1234) 20#define QEMU_VGA_DID (0x1111) 21 22#define bochs_vbe_dispi_read(base, reg) pcie_read16(base + (0x500 + (reg << 1))) 23#define bochs_vbe_dispi_write(base, reg, val) pcie_write16(base + (0x500 + (reg << 1)), val) 24 25#define BOCHS_VBE_DISPI_ID 0x0 26#define BOCHS_VBE_DISPI_XRES 0x1 27#define BOCHS_VBE_DISPI_YRES 0x2 28#define BOCHS_VBE_DISPI_BPP 0x3 29#define BOCHS_VBE_DISPI_ENABLE 0x4 30#define BOCHS_VBE_DISPI_BANK 0x5 31#define BOCHS_VBE_DISPI_VIRT_WIDTH 0x6 32#define BOCHS_VBE_DISPI_VIRT_HEIGHT 0x7 33#define BOCHS_VBE_DISPI_X_OFFSET 0x8 34#define BOCHS_VBE_DISPI_Y_OFFSET 0x9 35#define BOCHS_VBE_DISPI_VIDEO_MEMORY_64K 0xa 36 37static int zx_display_format_to_bpp(zx_pixel_format_t format) { 38 unsigned bpp = ZX_PIXEL_FORMAT_BYTES(format) * 8; 39 if (bpp == 0) { 40 // unknown 41 return -1; 42 } else { 43 return bpp; 44 } 45} 46 47static void set_hw_mode(void* regs, uint16_t width, uint16_t height, zx_pixel_format_t format) { 48 zxlogf(SPEW, "id: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_ID)); 49 50 int bpp = zx_display_format_to_bpp(format); 51 assert(bpp >= 0); 52 53 bochs_vbe_dispi_write(regs, BOCHS_VBE_DISPI_ENABLE, 0); 54 bochs_vbe_dispi_write(regs, BOCHS_VBE_DISPI_BPP, bpp); 55 bochs_vbe_dispi_write(regs, BOCHS_VBE_DISPI_XRES, width); 56 bochs_vbe_dispi_write(regs, BOCHS_VBE_DISPI_YRES, height); 57 bochs_vbe_dispi_write(regs, BOCHS_VBE_DISPI_BANK, 0); 58 bochs_vbe_dispi_write(regs, BOCHS_VBE_DISPI_VIRT_WIDTH, width); 59 bochs_vbe_dispi_write(regs, BOCHS_VBE_DISPI_VIRT_HEIGHT, height); 60 bochs_vbe_dispi_write(regs, BOCHS_VBE_DISPI_X_OFFSET, 0); 61 bochs_vbe_dispi_write(regs, BOCHS_VBE_DISPI_Y_OFFSET, 0); 62 bochs_vbe_dispi_write(regs, BOCHS_VBE_DISPI_ENABLE, 0x41); 63 64 zxlogf(SPEW, "bochs_vbe_set_hw_mode:\n"); 65 zxlogf(SPEW, " ID: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_ID)); 66 zxlogf(SPEW, " XRES: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_XRES)); 67 zxlogf(SPEW, " YRES: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_YRES)); 68 zxlogf(SPEW, " BPP: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_BPP)); 69 zxlogf(SPEW, " ENABLE: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_ENABLE)); 70 zxlogf(SPEW, " BANK: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_BANK)); 71 zxlogf(SPEW, "VWIDTH: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_VIRT_WIDTH)); 72 zxlogf(SPEW, "VHEIGHT: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_VIRT_HEIGHT)); 73 zxlogf(SPEW, " XOFF: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_X_OFFSET)); 74 zxlogf(SPEW, " YOFF: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_Y_OFFSET)); 75 zxlogf(SPEW, " 64K: 0x%x\n", bochs_vbe_dispi_read(regs, BOCHS_VBE_DISPI_VIDEO_MEMORY_64K)); 76} 77 78static zx_status_t bochs_vbe_bind(void* ctx, zx_device_t* dev) { 79 pci_protocol_t pci; 80 zx_status_t status; 81 82 if (device_get_protocol(dev, ZX_PROTOCOL_PCI, &pci)) 83 return ZX_ERR_NOT_SUPPORTED; 84 85 void* regs; 86 uint64_t regs_size; 87 zx_handle_t regs_handle; 88 // map register window 89 status = pci_map_bar(&pci, 2u, ZX_CACHE_POLICY_UNCACHED_DEVICE, 90 ®s, ®s_size, ®s_handle); 91 if (status != ZX_OK) { 92 printf("bochs-vbe: failed to map pci config: %d\n", status); 93 return status; 94 } 95 96 set_hw_mode(regs, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_FORMAT); 97 98 zx_handle_close(regs_handle); 99 zx_vmar_unmap(zx_vmar_root_self(), (uintptr_t) regs, regs_size); 100 101 return bind_simple_pci_display(dev, "bochs_vbe", 0u, 102 DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_WIDTH, DISPLAY_FORMAT); 103} 104 105static zx_driver_ops_t bochs_vbe_driver_ops = { 106 .version = DRIVER_OPS_VERSION, 107 .bind = bochs_vbe_bind, 108}; 109 110// clang-format off 111ZIRCON_DRIVER_BEGIN(bochs_vbe, bochs_vbe_driver_ops, "zircon", "0.1", 3) 112 BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PCI), 113 BI_ABORT_IF(NE, BIND_PCI_VID, QEMU_VGA_VID), 114 BI_MATCH_IF(EQ, BIND_PCI_DID, QEMU_VGA_DID), 115ZIRCON_DRIVER_END(bochs_vbe) 116