linux/drivers/gpu/drm/bochs/bochs_hw.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License as published by
   4 * the Free Software Foundation; either version 2 of the License, or
   5 * (at your option) any later version.
   6 */
   7
   8#include "bochs.h"
   9
  10/* ---------------------------------------------------------------------- */
  11
  12static void bochs_vga_writeb(struct bochs_device *bochs, u16 ioport, u8 val)
  13{
  14        if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df))
  15                return;
  16
  17        if (bochs->mmio) {
  18                int offset = ioport - 0x3c0 + 0x400;
  19                writeb(val, bochs->mmio + offset);
  20        } else {
  21                outb(val, ioport);
  22        }
  23}
  24
  25static u16 bochs_dispi_read(struct bochs_device *bochs, u16 reg)
  26{
  27        u16 ret = 0;
  28
  29        if (bochs->mmio) {
  30                int offset = 0x500 + (reg << 1);
  31                ret = readw(bochs->mmio + offset);
  32        } else {
  33                outw(reg, VBE_DISPI_IOPORT_INDEX);
  34                ret = inw(VBE_DISPI_IOPORT_DATA);
  35        }
  36        return ret;
  37}
  38
  39static void bochs_dispi_write(struct bochs_device *bochs, u16 reg, u16 val)
  40{
  41        if (bochs->mmio) {
  42                int offset = 0x500 + (reg << 1);
  43                writew(val, bochs->mmio + offset);
  44        } else {
  45                outw(reg, VBE_DISPI_IOPORT_INDEX);
  46                outw(val, VBE_DISPI_IOPORT_DATA);
  47        }
  48}
  49
  50int bochs_hw_init(struct drm_device *dev, uint32_t flags)
  51{
  52        struct bochs_device *bochs = dev->dev_private;
  53        struct pci_dev *pdev = dev->pdev;
  54        unsigned long addr, size, mem, ioaddr, iosize;
  55        u16 id;
  56
  57        if (/* (ent->driver_data == BOCHS_QEMU_STDVGA) && */
  58            (pdev->resource[2].flags & IORESOURCE_MEM)) {
  59                /* mmio bar with vga and bochs registers present */
  60                if (pci_request_region(pdev, 2, "bochs-drm") != 0) {
  61                        DRM_ERROR("Cannot request mmio region\n");
  62                        return -EBUSY;
  63                }
  64                ioaddr = pci_resource_start(pdev, 2);
  65                iosize = pci_resource_len(pdev, 2);
  66                bochs->mmio = ioremap(ioaddr, iosize);
  67                if (bochs->mmio == NULL) {
  68                        DRM_ERROR("Cannot map mmio region\n");
  69                        return -ENOMEM;
  70                }
  71        } else {
  72                ioaddr = VBE_DISPI_IOPORT_INDEX;
  73                iosize = 2;
  74                if (!request_region(ioaddr, iosize, "bochs-drm")) {
  75                        DRM_ERROR("Cannot request ioports\n");
  76                        return -EBUSY;
  77                }
  78                bochs->ioports = 1;
  79        }
  80
  81        id = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID);
  82        mem = bochs_dispi_read(bochs, VBE_DISPI_INDEX_VIDEO_MEMORY_64K)
  83                * 64 * 1024;
  84        if ((id & 0xfff0) != VBE_DISPI_ID0) {
  85                DRM_ERROR("ID mismatch\n");
  86                return -ENODEV;
  87        }
  88
  89        if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0)
  90                return -ENODEV;
  91        addr = pci_resource_start(pdev, 0);
  92        size = pci_resource_len(pdev, 0);
  93        if (addr == 0)
  94                return -ENODEV;
  95        if (size != mem) {
  96                DRM_ERROR("Size mismatch: pci=%ld, bochs=%ld\n",
  97                        size, mem);
  98                size = min(size, mem);
  99        }
 100
 101        if (pci_request_region(pdev, 0, "bochs-drm") != 0) {
 102                DRM_ERROR("Cannot request framebuffer\n");
 103                return -EBUSY;
 104        }
 105
 106        bochs->fb_map = ioremap(addr, size);
 107        if (bochs->fb_map == NULL) {
 108                DRM_ERROR("Cannot map framebuffer\n");
 109                return -ENOMEM;
 110        }
 111        bochs->fb_base = addr;
 112        bochs->fb_size = size;
 113
 114        DRM_INFO("Found bochs VGA, ID 0x%x.\n", id);
 115        DRM_INFO("Framebuffer size %ld kB @ 0x%lx, %s @ 0x%lx.\n",
 116                 size / 1024, addr,
 117                 bochs->ioports ? "ioports" : "mmio",
 118                 ioaddr);
 119        return 0;
 120}
 121
 122void bochs_hw_fini(struct drm_device *dev)
 123{
 124        struct bochs_device *bochs = dev->dev_private;
 125
 126        if (bochs->mmio)
 127                iounmap(bochs->mmio);
 128        if (bochs->ioports)
 129                release_region(VBE_DISPI_IOPORT_INDEX, 2);
 130        if (bochs->fb_map)
 131                iounmap(bochs->fb_map);
 132        pci_release_regions(dev->pdev);
 133}
 134
 135void bochs_hw_setmode(struct bochs_device *bochs,
 136                      struct drm_display_mode *mode)
 137{
 138        bochs->xres = mode->hdisplay;
 139        bochs->yres = mode->vdisplay;
 140        bochs->bpp = 32;
 141        bochs->stride = mode->hdisplay * (bochs->bpp / 8);
 142        bochs->yres_virtual = bochs->fb_size / bochs->stride;
 143
 144        DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n",
 145                         bochs->xres, bochs->yres, bochs->bpp,
 146                         bochs->yres_virtual);
 147
 148        bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
 149
 150        bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP,         bochs->bpp);
 151        bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES,        bochs->xres);
 152        bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES,        bochs->yres);
 153        bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK,        0);
 154        bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH,  bochs->xres);
 155        bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT,
 156                          bochs->yres_virtual);
 157        bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET,    0);
 158        bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET,    0);
 159
 160        bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,
 161                          VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
 162}
 163
 164void bochs_hw_setbase(struct bochs_device *bochs,
 165                      int x, int y, u64 addr)
 166{
 167        unsigned long offset = (unsigned long)addr +
 168                y * bochs->stride +
 169                x * (bochs->bpp / 8);
 170        int vy = offset / bochs->stride;
 171        int vx = (offset % bochs->stride) * 8 / bochs->bpp;
 172
 173        DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n",
 174                         x, y, addr, offset, vx, vy);
 175        bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx);
 176        bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy);
 177}
 178