.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
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 | 3 | */ |
---|
| 4 | + |
---|
| 5 | +#include <linux/pci.h> |
---|
| 6 | + |
---|
| 7 | +#include <drm/drm_drv.h> |
---|
| 8 | +#include <drm/drm_fourcc.h> |
---|
7 | 9 | |
---|
8 | 10 | #include "bochs.h" |
---|
9 | 11 | |
---|
.. | .. |
---|
47 | 49 | } |
---|
48 | 50 | } |
---|
49 | 51 | |
---|
50 | | -int bochs_hw_init(struct drm_device *dev, uint32_t flags) |
---|
| 52 | +static void bochs_hw_set_big_endian(struct bochs_device *bochs) |
---|
| 53 | +{ |
---|
| 54 | + if (bochs->qext_size < 8) |
---|
| 55 | + return; |
---|
| 56 | + |
---|
| 57 | + writel(0xbebebebe, bochs->mmio + 0x604); |
---|
| 58 | +} |
---|
| 59 | + |
---|
| 60 | +static void bochs_hw_set_little_endian(struct bochs_device *bochs) |
---|
| 61 | +{ |
---|
| 62 | + if (bochs->qext_size < 8) |
---|
| 63 | + return; |
---|
| 64 | + |
---|
| 65 | + writel(0x1e1e1e1e, bochs->mmio + 0x604); |
---|
| 66 | +} |
---|
| 67 | + |
---|
| 68 | +#ifdef __BIG_ENDIAN |
---|
| 69 | +#define bochs_hw_set_native_endian(_b) bochs_hw_set_big_endian(_b) |
---|
| 70 | +#else |
---|
| 71 | +#define bochs_hw_set_native_endian(_b) bochs_hw_set_little_endian(_b) |
---|
| 72 | +#endif |
---|
| 73 | + |
---|
| 74 | +static int bochs_get_edid_block(void *data, u8 *buf, |
---|
| 75 | + unsigned int block, size_t len) |
---|
| 76 | +{ |
---|
| 77 | + struct bochs_device *bochs = data; |
---|
| 78 | + size_t i, start = block * EDID_LENGTH; |
---|
| 79 | + |
---|
| 80 | + if (start + len > 0x400 /* vga register offset */) |
---|
| 81 | + return -1; |
---|
| 82 | + |
---|
| 83 | + for (i = 0; i < len; i++) { |
---|
| 84 | + buf[i] = readb(bochs->mmio + start + i); |
---|
| 85 | + } |
---|
| 86 | + return 0; |
---|
| 87 | +} |
---|
| 88 | + |
---|
| 89 | +int bochs_hw_load_edid(struct bochs_device *bochs) |
---|
| 90 | +{ |
---|
| 91 | + u8 header[8]; |
---|
| 92 | + |
---|
| 93 | + if (!bochs->mmio) |
---|
| 94 | + return -1; |
---|
| 95 | + |
---|
| 96 | + /* check header to detect whenever edid support is enabled in qemu */ |
---|
| 97 | + bochs_get_edid_block(bochs, header, 0, ARRAY_SIZE(header)); |
---|
| 98 | + if (drm_edid_header_is_valid(header) != 8) |
---|
| 99 | + return -1; |
---|
| 100 | + |
---|
| 101 | + kfree(bochs->edid); |
---|
| 102 | + bochs->edid = drm_do_get_edid(&bochs->connector, |
---|
| 103 | + bochs_get_edid_block, bochs); |
---|
| 104 | + if (bochs->edid == NULL) |
---|
| 105 | + return -1; |
---|
| 106 | + |
---|
| 107 | + return 0; |
---|
| 108 | +} |
---|
| 109 | + |
---|
| 110 | +int bochs_hw_init(struct drm_device *dev) |
---|
51 | 111 | { |
---|
52 | 112 | struct bochs_device *bochs = dev->dev_private; |
---|
53 | 113 | struct pci_dev *pdev = dev->pdev; |
---|
54 | | - unsigned long addr, size, mem, ioaddr, iosize, qext_size; |
---|
| 114 | + unsigned long addr, size, mem, ioaddr, iosize; |
---|
55 | 115 | u16 id; |
---|
56 | 116 | |
---|
57 | 117 | if (pdev->resource[2].flags & IORESOURCE_MEM) { |
---|
.. | .. |
---|
115 | 175 | ioaddr); |
---|
116 | 176 | |
---|
117 | 177 | if (bochs->mmio && pdev->revision >= 2) { |
---|
118 | | - qext_size = readl(bochs->mmio + 0x600); |
---|
119 | | - if (qext_size < 4 || qext_size > iosize) |
---|
| 178 | + bochs->qext_size = readl(bochs->mmio + 0x600); |
---|
| 179 | + if (bochs->qext_size < 4 || bochs->qext_size > iosize) { |
---|
| 180 | + bochs->qext_size = 0; |
---|
120 | 181 | goto noext; |
---|
121 | | - DRM_DEBUG("Found qemu ext regs, size %ld\n", qext_size); |
---|
122 | | - if (qext_size >= 8) { |
---|
123 | | -#ifdef __BIG_ENDIAN |
---|
124 | | - writel(0xbebebebe, bochs->mmio + 0x604); |
---|
125 | | -#else |
---|
126 | | - writel(0x1e1e1e1e, bochs->mmio + 0x604); |
---|
127 | | -#endif |
---|
128 | | - DRM_DEBUG(" qext endian: 0x%x\n", |
---|
129 | | - readl(bochs->mmio + 0x604)); |
---|
130 | 182 | } |
---|
| 183 | + DRM_DEBUG("Found qemu ext regs, size %ld\n", |
---|
| 184 | + bochs->qext_size); |
---|
| 185 | + bochs_hw_set_native_endian(bochs); |
---|
131 | 186 | } |
---|
132 | 187 | |
---|
133 | 188 | noext: |
---|
.. | .. |
---|
138 | 193 | { |
---|
139 | 194 | struct bochs_device *bochs = dev->dev_private; |
---|
140 | 195 | |
---|
| 196 | + /* TODO: shot down existing vram mappings */ |
---|
| 197 | + |
---|
141 | 198 | if (bochs->mmio) |
---|
142 | 199 | iounmap(bochs->mmio); |
---|
143 | 200 | if (bochs->ioports) |
---|
.. | .. |
---|
145 | 202 | if (bochs->fb_map) |
---|
146 | 203 | iounmap(bochs->fb_map); |
---|
147 | 204 | pci_release_regions(dev->pdev); |
---|
| 205 | + kfree(bochs->edid); |
---|
148 | 206 | } |
---|
149 | 207 | |
---|
150 | 208 | void bochs_hw_setmode(struct bochs_device *bochs, |
---|
151 | 209 | struct drm_display_mode *mode) |
---|
152 | 210 | { |
---|
| 211 | + int idx; |
---|
| 212 | + |
---|
| 213 | + if (!drm_dev_enter(bochs->dev, &idx)) |
---|
| 214 | + return; |
---|
| 215 | + |
---|
153 | 216 | bochs->xres = mode->hdisplay; |
---|
154 | 217 | bochs->yres = mode->vdisplay; |
---|
155 | 218 | bochs->bpp = 32; |
---|
.. | .. |
---|
175 | 238 | |
---|
176 | 239 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, |
---|
177 | 240 | VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); |
---|
| 241 | + |
---|
| 242 | + drm_dev_exit(idx); |
---|
| 243 | +} |
---|
| 244 | + |
---|
| 245 | +void bochs_hw_setformat(struct bochs_device *bochs, |
---|
| 246 | + const struct drm_format_info *format) |
---|
| 247 | +{ |
---|
| 248 | + int idx; |
---|
| 249 | + |
---|
| 250 | + if (!drm_dev_enter(bochs->dev, &idx)) |
---|
| 251 | + return; |
---|
| 252 | + |
---|
| 253 | + DRM_DEBUG_DRIVER("format %c%c%c%c\n", |
---|
| 254 | + (format->format >> 0) & 0xff, |
---|
| 255 | + (format->format >> 8) & 0xff, |
---|
| 256 | + (format->format >> 16) & 0xff, |
---|
| 257 | + (format->format >> 24) & 0xff); |
---|
| 258 | + |
---|
| 259 | + switch (format->format) { |
---|
| 260 | + case DRM_FORMAT_XRGB8888: |
---|
| 261 | + bochs_hw_set_little_endian(bochs); |
---|
| 262 | + break; |
---|
| 263 | + case DRM_FORMAT_BGRX8888: |
---|
| 264 | + bochs_hw_set_big_endian(bochs); |
---|
| 265 | + break; |
---|
| 266 | + default: |
---|
| 267 | + /* should not happen */ |
---|
| 268 | + DRM_ERROR("%s: Huh? Got framebuffer format 0x%x", |
---|
| 269 | + __func__, format->format); |
---|
| 270 | + break; |
---|
| 271 | + } |
---|
| 272 | + |
---|
| 273 | + drm_dev_exit(idx); |
---|
178 | 274 | } |
---|
179 | 275 | |
---|
180 | 276 | void bochs_hw_setbase(struct bochs_device *bochs, |
---|
181 | | - int x, int y, u64 addr) |
---|
| 277 | + int x, int y, int stride, u64 addr) |
---|
182 | 278 | { |
---|
183 | | - unsigned long offset = (unsigned long)addr + |
---|
| 279 | + unsigned long offset; |
---|
| 280 | + unsigned int vx, vy, vwidth, idx; |
---|
| 281 | + |
---|
| 282 | + if (!drm_dev_enter(bochs->dev, &idx)) |
---|
| 283 | + return; |
---|
| 284 | + |
---|
| 285 | + bochs->stride = stride; |
---|
| 286 | + offset = (unsigned long)addr + |
---|
184 | 287 | y * bochs->stride + |
---|
185 | 288 | x * (bochs->bpp / 8); |
---|
186 | | - int vy = offset / bochs->stride; |
---|
187 | | - int vx = (offset % bochs->stride) * 8 / bochs->bpp; |
---|
| 289 | + vy = offset / bochs->stride; |
---|
| 290 | + vx = (offset % bochs->stride) * 8 / bochs->bpp; |
---|
| 291 | + vwidth = stride * 8 / bochs->bpp; |
---|
188 | 292 | |
---|
189 | 293 | DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n", |
---|
190 | 294 | x, y, addr, offset, vx, vy); |
---|
| 295 | + bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, vwidth); |
---|
191 | 296 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx); |
---|
192 | 297 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy); |
---|
| 298 | + |
---|
| 299 | + drm_dev_exit(idx); |
---|
193 | 300 | } |
---|