/*
 * Copyright 2013 Matrox Graphics
 *
 * This file is subject to the terms and conditions of the GNU General
 * Public License version 2. See the file COPYING in the main
 * directory of this archive for more details.
 *
 * Author: Christopher Harvey <charvey@matrox.com>
 */

#include <drm/drmP.h>
#include "mgag200_drv.h"

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

/*
  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 mga_hide_cursor(struct mga_device *mdev)
{
	WREG8(MGA_CURPOSXL, 0);
	WREG8(MGA_CURPOSXH, 0);
	if (mdev->cursor.pixels_1->pin_count)
		mgag200_bo_unpin(mdev->cursor.pixels_1);
	if (mdev->cursor.pixels_2->pin_count)
		mgag200_bo_unpin(mdev->cursor.pixels_2);
}

int mga_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 mgag200_bo *pixels_1 = mdev->cursor.pixels_1;
	struct mgag200_bo *pixels_2 = mdev->cursor.pixels_2;
	struct mgag200_bo *pixels_current = mdev->cursor.pixels_current;
	struct mgag200_bo *pixels_prev = mdev->cursor.pixels_prev;
	struct drm_gem_object *obj;
	struct mgag200_bo *bo = NULL;
	int ret = 0;
	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;
	u64 gpu_addr;
	u8 reg_index;
	u8 this_row[48];

	if (!pixels_1 || !pixels_2) {
		WREG8(MGA_CURPOSXL, 0);
		WREG8(MGA_CURPOSXH, 0);
		return -ENOTSUPP; /* Didn't allocate space for cursors */
	}

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

	BUG_ON(pixels_1 != pixels_current && pixels_1 != pixels_prev);
	BUG_ON(pixels_2 != pixels_current && pixels_2 != pixels_prev);
	BUG_ON(pixels_current == pixels_prev);

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

	obj = drm_gem_object_lookup(file_priv, handle);
	if (!obj)
		return -ENOENT;

	ret = mgag200_bo_reserve(pixels_1, true);
	if (ret) {
		WREG8(MGA_CURPOSXL, 0);
		WREG8(MGA_CURPOSXH, 0);
		goto out_unref;
	}
	ret = mgag200_bo_reserve(pixels_2, true);
	if (ret) {
		WREG8(MGA_CURPOSXL, 0);
		WREG8(MGA_CURPOSXH, 0);
		mgag200_bo_unreserve(pixels_1);
		goto out_unreserve1;
	}

	/* Move cursor buffers into VRAM if they aren't already */
	if (!pixels_1->pin_count) {
		ret = mgag200_bo_pin(pixels_1, TTM_PL_FLAG_VRAM,
				     &mdev->cursor.pixels_1_gpu_addr);
		if (ret)
			goto out1;
	}
	if (!pixels_2->pin_count) {
		ret = mgag200_bo_pin(pixels_2, TTM_PL_FLAG_VRAM,
				     &mdev->cursor.pixels_2_gpu_addr);
		if (ret) {
			mgag200_bo_unpin(pixels_1);
			goto out1;
		}
	}

	bo = gem_to_mga_bo(obj);
	ret = mgag200_bo_reserve(bo, true);
	if (ret) {
		dev_err(&dev->pdev->dev, "failed to reserve user bo\n");
		goto out1;
	}
	if (!bo->kmap.virtual) {
		ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
		if (ret) {
			dev_err(&dev->pdev->dev, "failed to kmap user buffer updates\n");
			goto out2;
		}
	}

	memset(&colour_set[0], 0, sizeof(uint32_t)*16);
	/* width*height*4 = 16384 */
	for (i = 0; i < 16384; i += 4) {
		this_colour = ioread32(bo->kmap.virtual + 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. */
			}
			ret = -EINVAL;
			goto out3;
		}
		/* 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. */
			}
			ret = -EINVAL;
			goto out3;
		}
		*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);
	}

	/* Map up-coming buffer to write colour indices */
	if (!pixels_prev->kmap.virtual) {
		ret = ttm_bo_kmap(&pixels_prev->bo, 0,
				  pixels_prev->bo.num_pages,
				  &pixels_prev->kmap);
		if (ret) {
			dev_err(&dev->pdev->dev, "failed to kmap cursor updates\n");
			goto out3;
		}
	}

	/* 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(bo->kmap.virtual + 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(pixels_prev->kmap.virtual + row*48, &this_row[0], 48);
	}

	/* Program gpu address of cursor buffer */
	if (pixels_prev == pixels_1)
		gpu_addr = mdev->cursor.pixels_1_gpu_addr;
	else
		gpu_addr = mdev->cursor.pixels_2_gpu_addr;
	WREG_DAC(MGA1064_CURSOR_BASE_ADR_LOW, (u8)((gpu_addr>>10) & 0xff));
	WREG_DAC(MGA1064_CURSOR_BASE_ADR_HI, (u8)((gpu_addr>>18) & 0x3f));

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

	/* Now swap internal buffer pointers */
	if (mdev->cursor.pixels_1 == mdev->cursor.pixels_prev) {
		mdev->cursor.pixels_prev = mdev->cursor.pixels_2;
		mdev->cursor.pixels_current = mdev->cursor.pixels_1;
	} else if (mdev->cursor.pixels_1 == mdev->cursor.pixels_current) {
		mdev->cursor.pixels_prev = mdev->cursor.pixels_1;
		mdev->cursor.pixels_current = mdev->cursor.pixels_2;
	} else {
		BUG();
	}
	ret = 0;

	ttm_bo_kunmap(&pixels_prev->kmap);
 out3:
	ttm_bo_kunmap(&bo->kmap);
 out2:
	mgag200_bo_unreserve(bo);
 out1:
	if (ret)
		mga_hide_cursor(mdev);
	mgag200_bo_unreserve(pixels_1);
out_unreserve1:
	mgag200_bo_unreserve(pixels_2);
out_unref:
	drm_gem_object_unreference_unlocked(obj);

	return ret;
}

int mga_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;

	BUG_ON(x <= 0);
	BUG_ON(y <= 0);
	BUG_ON(x & ~0xffff);
	BUG_ON(y & ~0xffff);

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

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