Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.1 273 lines 7.1 kB view raw
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 50static void bochs_hw_set_big_endian(struct bochs_device *bochs) 51{ 52 if (bochs->qext_size < 8) 53 return; 54 55 writel(0xbebebebe, bochs->mmio + 0x604); 56} 57 58static void bochs_hw_set_little_endian(struct bochs_device *bochs) 59{ 60 if (bochs->qext_size < 8) 61 return; 62 63 writel(0x1e1e1e1e, bochs->mmio + 0x604); 64} 65 66#ifdef __BIG_ENDIAN 67#define bochs_hw_set_native_endian(_b) bochs_hw_set_big_endian(_b) 68#else 69#define bochs_hw_set_native_endian(_b) bochs_hw_set_little_endian(_b) 70#endif 71 72static int bochs_get_edid_block(void *data, u8 *buf, 73 unsigned int block, size_t len) 74{ 75 struct bochs_device *bochs = data; 76 size_t i, start = block * EDID_LENGTH; 77 78 if (start + len > 0x400 /* vga register offset */) 79 return -1; 80 81 for (i = 0; i < len; i++) { 82 buf[i] = readb(bochs->mmio + start + i); 83 } 84 return 0; 85} 86 87int bochs_hw_load_edid(struct bochs_device *bochs) 88{ 89 u8 header[8]; 90 91 if (!bochs->mmio) 92 return -1; 93 94 /* check header to detect whenever edid support is enabled in qemu */ 95 bochs_get_edid_block(bochs, header, 0, ARRAY_SIZE(header)); 96 if (drm_edid_header_is_valid(header) != 8) 97 return -1; 98 99 kfree(bochs->edid); 100 bochs->edid = drm_do_get_edid(&bochs->connector, 101 bochs_get_edid_block, bochs); 102 if (bochs->edid == NULL) 103 return -1; 104 105 return 0; 106} 107 108int bochs_hw_init(struct drm_device *dev) 109{ 110 struct bochs_device *bochs = dev->dev_private; 111 struct pci_dev *pdev = dev->pdev; 112 unsigned long addr, size, mem, ioaddr, iosize; 113 u16 id; 114 115 if (pdev->resource[2].flags & IORESOURCE_MEM) { 116 /* mmio bar with vga and bochs registers present */ 117 if (pci_request_region(pdev, 2, "bochs-drm") != 0) { 118 DRM_ERROR("Cannot request mmio region\n"); 119 return -EBUSY; 120 } 121 ioaddr = pci_resource_start(pdev, 2); 122 iosize = pci_resource_len(pdev, 2); 123 bochs->mmio = ioremap(ioaddr, iosize); 124 if (bochs->mmio == NULL) { 125 DRM_ERROR("Cannot map mmio region\n"); 126 return -ENOMEM; 127 } 128 } else { 129 ioaddr = VBE_DISPI_IOPORT_INDEX; 130 iosize = 2; 131 if (!request_region(ioaddr, iosize, "bochs-drm")) { 132 DRM_ERROR("Cannot request ioports\n"); 133 return -EBUSY; 134 } 135 bochs->ioports = 1; 136 } 137 138 id = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID); 139 mem = bochs_dispi_read(bochs, VBE_DISPI_INDEX_VIDEO_MEMORY_64K) 140 * 64 * 1024; 141 if ((id & 0xfff0) != VBE_DISPI_ID0) { 142 DRM_ERROR("ID mismatch\n"); 143 return -ENODEV; 144 } 145 146 if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0) 147 return -ENODEV; 148 addr = pci_resource_start(pdev, 0); 149 size = pci_resource_len(pdev, 0); 150 if (addr == 0) 151 return -ENODEV; 152 if (size != mem) { 153 DRM_ERROR("Size mismatch: pci=%ld, bochs=%ld\n", 154 size, mem); 155 size = min(size, mem); 156 } 157 158 if (pci_request_region(pdev, 0, "bochs-drm") != 0) { 159 DRM_ERROR("Cannot request framebuffer\n"); 160 return -EBUSY; 161 } 162 163 bochs->fb_map = ioremap(addr, size); 164 if (bochs->fb_map == NULL) { 165 DRM_ERROR("Cannot map framebuffer\n"); 166 return -ENOMEM; 167 } 168 bochs->fb_base = addr; 169 bochs->fb_size = size; 170 171 DRM_INFO("Found bochs VGA, ID 0x%x.\n", id); 172 DRM_INFO("Framebuffer size %ld kB @ 0x%lx, %s @ 0x%lx.\n", 173 size / 1024, addr, 174 bochs->ioports ? "ioports" : "mmio", 175 ioaddr); 176 177 if (bochs->mmio && pdev->revision >= 2) { 178 bochs->qext_size = readl(bochs->mmio + 0x600); 179 if (bochs->qext_size < 4 || bochs->qext_size > iosize) { 180 bochs->qext_size = 0; 181 goto noext; 182 } 183 DRM_DEBUG("Found qemu ext regs, size %ld\n", 184 bochs->qext_size); 185 bochs_hw_set_native_endian(bochs); 186 } 187 188noext: 189 return 0; 190} 191 192void bochs_hw_fini(struct drm_device *dev) 193{ 194 struct bochs_device *bochs = dev->dev_private; 195 196 if (bochs->mmio) 197 iounmap(bochs->mmio); 198 if (bochs->ioports) 199 release_region(VBE_DISPI_IOPORT_INDEX, 2); 200 if (bochs->fb_map) 201 iounmap(bochs->fb_map); 202 pci_release_regions(dev->pdev); 203 kfree(bochs->edid); 204} 205 206void bochs_hw_setmode(struct bochs_device *bochs, 207 struct drm_display_mode *mode) 208{ 209 bochs->xres = mode->hdisplay; 210 bochs->yres = mode->vdisplay; 211 bochs->bpp = 32; 212 bochs->stride = mode->hdisplay * (bochs->bpp / 8); 213 bochs->yres_virtual = bochs->fb_size / bochs->stride; 214 215 DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n", 216 bochs->xres, bochs->yres, bochs->bpp, 217 bochs->yres_virtual); 218 219 bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */ 220 221 bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, 0); 222 bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP, bochs->bpp); 223 bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES, bochs->xres); 224 bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES, bochs->yres); 225 bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK, 0); 226 bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, bochs->xres); 227 bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT, 228 bochs->yres_virtual); 229 bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, 0); 230 bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, 0); 231 232 bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, 233 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); 234} 235 236void bochs_hw_setformat(struct bochs_device *bochs, 237 const struct drm_format_info *format) 238{ 239 DRM_DEBUG_DRIVER("format %c%c%c%c\n", 240 (format->format >> 0) & 0xff, 241 (format->format >> 8) & 0xff, 242 (format->format >> 16) & 0xff, 243 (format->format >> 24) & 0xff); 244 245 switch (format->format) { 246 case DRM_FORMAT_XRGB8888: 247 bochs_hw_set_little_endian(bochs); 248 break; 249 case DRM_FORMAT_BGRX8888: 250 bochs_hw_set_big_endian(bochs); 251 break; 252 default: 253 /* should not happen */ 254 DRM_ERROR("%s: Huh? Got framebuffer format 0x%x", 255 __func__, format->format); 256 break; 257 }; 258} 259 260void bochs_hw_setbase(struct bochs_device *bochs, 261 int x, int y, u64 addr) 262{ 263 unsigned long offset = (unsigned long)addr + 264 y * bochs->stride + 265 x * (bochs->bpp / 8); 266 int vy = offset / bochs->stride; 267 int vx = (offset % bochs->stride) * 8 / bochs->bpp; 268 269 DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n", 270 x, y, addr, offset, vx, vy); 271 bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx); 272 bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy); 273}