Commit 86351de0 authored by Gerd Hoffmann's avatar Gerd Hoffmann
Browse files

drm/bochs: support changing byteorder at mode set time



Add bochs_hw_set_*_endian() helper functions, to set the framebuffer
byteorder at mode set time.  Support both DRM_FORMAT_XRGB8888 and
DRM_FORMAT_BGRX8888 framebuffer formats, no matter what the native
machine byte order is.

Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
Acked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20180921134704.12826-5-kraxel@redhat.com
parent 48b44223
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ struct bochs_device {
	void __iomem   *fb_map;
	unsigned long  fb_base;
	unsigned long  fb_size;
	unsigned long  qext_size;

	/* mode */
	u16 xres;
@@ -121,7 +122,8 @@ int bochs_hw_init(struct drm_device *dev);
void bochs_hw_fini(struct drm_device *dev);

void bochs_hw_setmode(struct bochs_device *bochs,
		      struct drm_display_mode *mode);
		      struct drm_display_mode *mode,
		      const struct drm_format_info *format);
void bochs_hw_setbase(struct bochs_device *bochs,
		      int x, int y, u64 addr);

+2 −1
Original line number Diff line number Diff line
@@ -140,7 +140,8 @@ static struct drm_framebuffer *
bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file,
		    const struct drm_mode_fb_cmd2 *mode_cmd)
{
	if (mode_cmd->pixel_format != DRM_FORMAT_HOST_XRGB8888)
	if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888 &&
	    mode_cmd->pixel_format != DRM_FORMAT_BGRX8888)
		return ERR_PTR(-EINVAL);

	return drm_gem_fb_create(dev, file, mode_cmd);
+50 −14
Original line number Diff line number Diff line
@@ -47,11 +47,33 @@ static void bochs_dispi_write(struct bochs_device *bochs, u16 reg, u16 val)
	}
}

static void bochs_hw_set_big_endian(struct bochs_device *bochs)
{
	if (bochs->qext_size < 8)
		return;

	writel(0xbebebebe, bochs->mmio + 0x604);
}

static void bochs_hw_set_little_endian(struct bochs_device *bochs)
{
	if (bochs->qext_size < 8)
		return;

	writel(0x1e1e1e1e, bochs->mmio + 0x604);
}

#ifdef __BIG_ENDIAN
#define bochs_hw_set_native_endian(_b) bochs_hw_set_big_endian(_b)
#else
#define bochs_hw_set_native_endian(_b) bochs_hw_set_little_endian(_b)
#endif

int bochs_hw_init(struct drm_device *dev)
{
	struct bochs_device *bochs = dev->dev_private;
	struct pci_dev *pdev = dev->pdev;
	unsigned long addr, size, mem, ioaddr, iosize, qext_size;
	unsigned long addr, size, mem, ioaddr, iosize;
	u16 id;

	if (pdev->resource[2].flags & IORESOURCE_MEM) {
@@ -117,19 +139,14 @@ int bochs_hw_init(struct drm_device *dev)
		 ioaddr);

	if (bochs->mmio && pdev->revision >= 2) {
		qext_size = readl(bochs->mmio + 0x600);
		if (qext_size < 4 || qext_size > iosize)
		bochs->qext_size = readl(bochs->mmio + 0x600);
		if (bochs->qext_size < 4 || bochs->qext_size > iosize) {
			bochs->qext_size = 0;
			goto noext;
		DRM_DEBUG("Found qemu ext regs, size %ld\n", qext_size);
		if (qext_size >= 8) {
#ifdef __BIG_ENDIAN
			writel(0xbebebebe, bochs->mmio + 0x604);
#else
			writel(0x1e1e1e1e, bochs->mmio + 0x604);
#endif
			DRM_DEBUG("  qext endian: 0x%x\n",
				  readl(bochs->mmio + 0x604));
		}
		DRM_DEBUG("Found qemu ext regs, size %ld\n",
			  bochs->qext_size);
		bochs_hw_set_native_endian(bochs);
	}

noext:
@@ -150,7 +167,8 @@ void bochs_hw_fini(struct drm_device *dev)
}

void bochs_hw_setmode(struct bochs_device *bochs,
		      struct drm_display_mode *mode)
		      struct drm_display_mode *mode,
		      const struct drm_format_info *format)
{
	bochs->xres = mode->hdisplay;
	bochs->yres = mode->vdisplay;
@@ -158,8 +176,12 @@ void bochs_hw_setmode(struct bochs_device *bochs,
	bochs->stride = mode->hdisplay * (bochs->bpp / 8);
	bochs->yres_virtual = bochs->fb_size / bochs->stride;

	DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n",
	DRM_DEBUG_DRIVER("%dx%d @ %d bpp, format %c%c%c%c, vy %d\n",
			 bochs->xres, bochs->yres, bochs->bpp,
			 (format->format >>  0) & 0xff,
			 (format->format >>  8) & 0xff,
			 (format->format >> 16) & 0xff,
			 (format->format >> 24) & 0xff,
			 bochs->yres_virtual);

	bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
@@ -177,6 +199,20 @@ void bochs_hw_setmode(struct bochs_device *bochs,

	bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,
			  VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);

	switch (format->format) {
	case DRM_FORMAT_XRGB8888:
		bochs_hw_set_little_endian(bochs);
		break;
	case DRM_FORMAT_BGRX8888:
		bochs_hw_set_big_endian(bochs);
		break;
	default:
		/* should not happen */
		DRM_ERROR("%s: Huh? Got framebuffer format 0x%x",
			  __func__, format->format);
		break;
	};
}

void bochs_hw_setbase(struct bochs_device *bochs,
+6 −2
Original line number Diff line number Diff line
@@ -77,7 +77,10 @@ static int bochs_crtc_mode_set(struct drm_crtc *crtc,
	struct bochs_device *bochs =
		container_of(crtc, struct bochs_device, crtc);

	bochs_hw_setmode(bochs, mode);
	if (WARN_ON(crtc->primary->fb == NULL))
		return -EINVAL;

	bochs_hw_setmode(bochs, mode, crtc->primary->fb->format);
	bochs_crtc_mode_set_base(crtc, x, y, old_fb);
	return 0;
}
@@ -127,7 +130,8 @@ static const struct drm_crtc_helper_funcs bochs_helper_funcs = {
};

static const uint32_t bochs_formats[] = {
	DRM_FORMAT_HOST_XRGB8888,
	DRM_FORMAT_XRGB8888,
	DRM_FORMAT_BGRX8888,
};

static struct drm_plane *bochs_primary_plane(struct drm_device *dev)