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, qext_size;
  55        u16 id;
  56
  57        if (pdev->resource[2].flags & IORESOURCE_MEM) {
  58                /* mmio bar with vga and bochs registers present */
  59                if (pci_request_region(pdev, 2, "bochs-drm") != 0) {
  60                        DRM_ERROR("Cannot request mmio region\n");
  61                        return -EBUSY;
  62                }
  63                ioaddr = pci_resource_start(pdev, 2);
  64                iosize = pci_resource_len(pdev, 2);
  65                bochs->mmio = ioremap(ioaddr, iosize);
  66                if (bochs->mmio == NULL) {
  67                        DRM_ERROR("Cannot map mmio region\n");
  68                        return -ENOMEM;
  69                }
  70        } else {
  71                ioaddr = VBE_DISPI_IOPORT_INDEX;
  72                iosize = 2;
  73                if (!request_region(ioaddr, iosize, "bochs-drm")) {
  74                        DRM_ERROR("Cannot request ioports\n");
  75                        return -EBUSY;
  76                }
  77                bochs->ioports = 1;
  78        }
  79
  80        id = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID);
  81        mem = bochs_dispi_read(bochs, VBE_DISPI_INDEX_VIDEO_MEMORY_64K)
  82                * 64 * 1024;
  83        if ((id & 0xfff0) != VBE_DISPI_ID0) {
  84                DRM_ERROR("ID mismatch\n");
  85                return -ENODEV;
  86        }
  87
  88        if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0)
  89                return -ENODEV;
  90        addr = pci_resource_start(pdev, 0);
  91        size = pci_resource_len(pdev, 0);
  92        if (addr == 0)
  93                return -ENODEV;
  94        if (size != mem) {
  95                DRM_ERROR("Size mismatch: pci=%ld, bochs=%ld\n",
  96                        size, mem);
  97                size = min(size, mem);
  98        }
  99
 100        if (pci_request_region(pdev, 0, "bochs-drm") != 0) {
 101                DRM_ERROR("Cannot request framebuffer\n");
 102                return -EBUSY;
 103        }
 104
 105        bochs->fb_map = ioremap(addr, size);
 106        if (bochs->fb_map == NULL) {
 107                DRM_ERROR("Cannot map framebuffer\n");
 108                return -ENOMEM;
 109        }
 110        bochs->fb_base = addr;
 111        bochs->fb_size = size;
 112
 113        DRM_INFO("Found bochs VGA, ID 0x%x.\n", id);
 114        DRM_INFO("Framebuffer size %ld kB @ 0x%lx, %s @ 0x%lx.\n",
 115                 size / 1024, addr,
 116                 bochs->ioports ? "ioports" : "mmio",
 117                 ioaddr);
 118
 119        if (bochs->mmio && pdev->revision >= 2) {
 120                qext_size = readl(bochs->mmio + 0x600);
 121                if (qext_size < 4 || qext_size > iosize)
 122                        goto noext;
 123                DRM_DEBUG("Found qemu ext regs, size %ld\n", qext_size);
 124                if (qext_size >= 8) {
 125#ifdef __BIG_ENDIAN
 126                        writel(0xbebebebe, bochs->mmio + 0x604);
 127#else
 128                        writel(0x1e1e1e1e, bochs->mmio + 0x604);
 129#endif
 130                        DRM_DEBUG("  qext endian: 0x%x\n",
 131                                  readl(bochs->mmio + 0x604));
 132                }
 133        }
 134
 135noext:
 136        return 0;
 137}
 138
 139void bochs_hw_fini(struct drm_device *dev)
 140{
 141        struct bochs_device *bochs = dev->dev_private;
 142
 143        if (bochs->mmio)
 144                iounmap(bochs->mmio);
 145        if (bochs->ioports)
 146                release_region(VBE_DISPI_IOPORT_INDEX, 2);
 147        if (bochs->fb_map)
 148                iounmap(bochs->fb_map);
 149        pci_release_regions(dev->pdev);
 150}
 151
 152void bochs_hw_setmode(struct bochs_device *bochs,
 153                      struct drm_display_mode *mode)
 154{
 155        bochs->xres = mode->hdisplay;
 156        bochs->yres = mode->vdisplay;
 157        bochs->bpp = 32;
 158        bochs->stride = mode->hdisplay * (bochs->bpp / 8);
 159        bochs->yres_virtual = bochs->fb_size / bochs->stride;
 160
 161        DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n",
 162                         bochs->xres, bochs->yres, bochs->bpp,
 163                         bochs->yres_virtual);
 164
 165        bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
 166
 167        bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,      0);
 168        bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP,         bochs->bpp);
 169        bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES,        bochs->xres);
 170        bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES,        bochs->yres);
 171        bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK,        0);
 172        bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH,  bochs->xres);
 173        bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT,
 174                          bochs->yres_virtual);
 175        bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET,    0);
 176        bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET,    0);
 177
 178        bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,
 179                          VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
 180}
 181
 182void bochs_hw_setbase(struct bochs_device *bochs,
 183                      int x, int y, u64 addr)
 184{
 185        unsigned long offset = (unsigned long)addr +
 186                y * bochs->stride +
 187                x * (bochs->bpp / 8);
 188        int vy = offset / bochs->stride;
 189        int vx = (offset % bochs->stride) * 8 / bochs->bpp;
 190
 191        DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n",
 192                         x, y, addr, offset, vx, vy);
 193        bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx);
 194        bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy);
 195}
 196