// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2013 Matrox Graphics
 *
 * Author: Christopher Harvey <charvey@matrox.com>
 */

#include <drm/drm_pci.h>

#include "mgag200_drv.h"

static bool warn_transparent = true;
static bool warn_palette = true;

static int mgag200_cursor_update(struct mga_device *mdev, void *dst, void *src,
				 unsigned int width, unsigned int height)
{
	struct drm_device *dev = mdev->dev;
	unsigned int i, row, col;
	uint32_t colour_set[16];
	uint32_t *next_space = &colour_set[0];
	uint32_t *palette_iter;
	uint32_t this_colour;
	bool found = false;
	int colour_count = 0;
	u8 reg_index;
	u8 this_row[48];

	memset(&colour_set[0], 0, sizeof(uint32_t)*16);
	/* width*height*4 = 16384 */
	for (i = 0; i < 16384; i += 4) {
		this_colour = ioread32(src + i);
		/* No transparency */
		if (this_colour>>24 != 0xff &&
			this_colour>>24 != 0x0) {
			if (warn_transparent) {
				dev_info(&dev->pdev->dev, "Video card doesn't support cursors with partial transparency.\n");
				dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n");
				warn_transparent = false; /* Only tell the user once. */
			}
			return -EINVAL;
		}
		/* Don't need to store transparent pixels as colours */
		if (this_colour>>24 == 0x0)
			continue;
		found = false;
		for (palette_iter = &colour_set[0]; palette_iter != next_space; palette_iter++) {
			if (*palette_iter == this_colour) {
				found = true;
				break;
			}
		}
		if (found)
			continue;
		/* We only support 4bit paletted cursors */
		if (colour_count >= 16) {
			if (warn_palette) {
				dev_info(&dev->pdev->dev, "Video card only supports cursors with up to 16 colours.\n");
				dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n");
				warn_palette = false; /* Only tell the user once. */
			}
			return -EINVAL;
		}
		*next_space = this_colour;
		next_space++;
		colour_count++;
	}

	/* Program colours from cursor icon into palette */
	for (i = 0; i < colour_count; i++) {
		if (i <= 2)
			reg_index = 0x8 + i*0x4;
		else
			reg_index = 0x60 + i*0x3;
		WREG_DAC(reg_index, colour_set[i] & 0xff);
		WREG_DAC(reg_index+1, colour_set[i]>>8 & 0xff);
		WREG_DAC(reg_index+2, colour_set[i]>>16 & 0xff);
		BUG_ON((colour_set[i]>>24 & 0xff) != 0xff);
	}

	/* now write colour indices into hardware cursor buffer */
	for (row = 0; row < 64; row++) {
		memset(&this_row[0], 0, 48);
		for (col = 0; col < 64; col++) {
			this_colour = ioread32(src + 4*(col + 64*row));
			/* write transparent pixels */
			if (this_colour>>24 == 0x0) {
				this_row[47 - col/8] |= 0x80>>(col%8);
				continue;
			}

			/* write colour index here */
			for (i = 0; i < colour_count; i++) {
				if (colour_set[i] == this_colour) {
					if (col % 2)
						this_row[col/2] |= i<<4;
					else
						this_row[col/2] |= i;
					break;
				}
			}
		}
		memcpy_toio(dst + row*48, &this_row[0], 48);
	}

	return 0;
}

static void mgag200_cursor_set_base(struct mga_device *mdev, u64 address)
{
	u8 addrl = (address >> 10) & 0xff;
	u8 addrh = (address >> 18) & 0x3f;

	/* Program gpu address of cursor buffer */
	WREG_DAC(MGA1064_CURSOR_BASE_ADR_LOW, addrl);
	WREG_DAC(MGA1064_CURSOR_BASE_ADR_HI, addrh);
}

static int mgag200_show_cursor(struct mga_device *mdev, void *src,
			       unsigned int width, unsigned int height)
{
	struct drm_device *dev = mdev->dev;
	struct drm_gem_vram_object *gbo;
	void *dst;
	s64 off;
	int ret;

	gbo = mdev->cursor.gbo[mdev->cursor.next_index];
	if (!gbo) {
		WREG8(MGA_CURPOSXL, 0);
		WREG8(MGA_CURPOSXH, 0);
		return -ENOTSUPP; /* Didn't allocate space for cursors */
	}
	dst = drm_gem_vram_vmap(gbo);
	if (IS_ERR(dst)) {
		ret = PTR_ERR(dst);
		dev_err(&dev->pdev->dev,
			"failed to map cursor updates: %d\n", ret);
		return ret;
	}
	off = drm_gem_vram_offset(gbo);
	if (off < 0) {
		ret = (int)off;
		dev_err(&dev->pdev->dev,
			"failed to get cursor scanout address: %d\n", ret);
		goto err_drm_gem_vram_vunmap;
	}

	ret = mgag200_cursor_update(mdev, dst, src, width, height);
	if (ret)
		goto err_drm_gem_vram_vunmap;
	mgag200_cursor_set_base(mdev, off);

	/* Adjust cursor control register to turn on the cursor */
	WREG_DAC(MGA1064_CURSOR_CTL, 4); /* 16-colour palletized cursor mode */

	drm_gem_vram_vunmap(gbo, dst);

	++mdev->cursor.next_index;
	mdev->cursor.next_index %= ARRAY_SIZE(mdev->cursor.gbo);

	return 0;

err_drm_gem_vram_vunmap:
	drm_gem_vram_vunmap(gbo, dst);
	return ret;
}

/*
 * Hide the cursor off screen. We can't disable the cursor hardware because
 * it takes too long to re-activate and causes momentary corruption.
 */
static void mgag200_hide_cursor(struct mga_device *mdev)
{
	WREG8(MGA_CURPOSXL, 0);
	WREG8(MGA_CURPOSXH, 0);
}

static void mgag200_move_cursor(struct mga_device *mdev, int x, int y)
{
	if (WARN_ON(x <= 0))
		return;
	if (WARN_ON(y <= 0))
		return;
	if (WARN_ON(x & ~0xffff))
		return;
	if (WARN_ON(y & ~0xffff))
		return;

	WREG8(MGA_CURPOSXL, x & 0xff);
	WREG8(MGA_CURPOSXH, (x>>8) & 0xff);

	WREG8(MGA_CURPOSYL, y & 0xff);
	WREG8(MGA_CURPOSYH, (y>>8) & 0xff);
}

int mgag200_cursor_init(struct mga_device *mdev)
{
	struct drm_device *dev = mdev->dev;
	size_t ncursors = ARRAY_SIZE(mdev->cursor.gbo);
	size_t size;
	int ret;
	size_t i;
	struct drm_gem_vram_object *gbo;

	size = roundup(64 * 48, PAGE_SIZE);
	if (size * ncursors > mdev->vram_fb_available)
		return -ENOMEM;

	for (i = 0; i < ncursors; ++i) {
		gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev,
					  size, 0, false);
		if (IS_ERR(gbo)) {
			ret = PTR_ERR(gbo);
			goto err_drm_gem_vram_put;
		}
		ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM |
					    DRM_GEM_VRAM_PL_FLAG_TOPDOWN);
		if (ret) {
			drm_gem_vram_put(gbo);
			goto err_drm_gem_vram_put;
		}

		mdev->cursor.gbo[i] = gbo;
	}

	/*
	 * At the high end of video memory, we reserve space for
	 * buffer objects. The cursor plane uses this memory to store
	 * a double-buffered image of the current cursor. Hence, it's
	 * not available for framebuffers.
	 */
	mdev->vram_fb_available -= ncursors * size;

	return 0;

err_drm_gem_vram_put:
	while (i) {
		--i;
		gbo = mdev->cursor.gbo[i];
		drm_gem_vram_unpin(gbo);
		drm_gem_vram_put(gbo);
		mdev->cursor.gbo[i] = NULL;
	}
	return ret;
}

void mgag200_cursor_fini(struct mga_device *mdev)
{
	size_t i;
	struct drm_gem_vram_object *gbo;

	for (i = 0; i < ARRAY_SIZE(mdev->cursor.gbo); ++i) {
		gbo = mdev->cursor.gbo[i];
		drm_gem_vram_unpin(gbo);
		drm_gem_vram_put(gbo);
	}
}

int mgag200_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
			    uint32_t handle, uint32_t width, uint32_t height)
{
	struct drm_device *dev = crtc->dev;
	struct mga_device *mdev = (struct mga_device *)dev->dev_private;
	struct drm_gem_object *obj;
	struct drm_gem_vram_object *gbo = NULL;
	int ret;
	u8 *src;

	if (!handle || !file_priv) {
		mgag200_hide_cursor(mdev);
		return 0;
	}

	if (width != 64 || height != 64) {
		WREG8(MGA_CURPOSXL, 0);
		WREG8(MGA_CURPOSXH, 0);
		return -EINVAL;
	}

	obj = drm_gem_object_lookup(file_priv, handle);
	if (!obj)
		return -ENOENT;
	gbo = drm_gem_vram_of_gem(obj);
	src = drm_gem_vram_vmap(gbo);
	if (IS_ERR(src)) {
		ret = PTR_ERR(src);
		dev_err(&dev->pdev->dev,
			"failed to map user buffer updates\n");
		goto err_drm_gem_object_put_unlocked;
	}

	ret = mgag200_show_cursor(mdev, src, width, height);
	if (ret)
		goto err_drm_gem_vram_vunmap;

	/* Now update internal buffer pointers */
	drm_gem_vram_vunmap(gbo, src);
	drm_gem_object_put_unlocked(obj);

	return 0;
err_drm_gem_vram_vunmap:
	drm_gem_vram_vunmap(gbo, src);
err_drm_gem_object_put_unlocked:
	drm_gem_object_put_unlocked(obj);
	return ret;
}

int mgag200_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
{
	struct mga_device *mdev = (struct mga_device *)crtc->dev->dev_private;

	/* Our origin is at (64,64) */
	x += 64;
	y += 64;

	mgag200_move_cursor(mdev, x, y);

	return 0;
}
