12ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov/*
22ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * drivers/mb862xx/mb862xxfb_accel.c
32ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov *
42ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver acceleration support
52ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov *
62ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * (C) 2007 Alexander Shishkin <virtuoso@slind.org>
7da258016293f5e82b36db67ac3db3931a4fbbc4dAlexander Shishkin * (C) 2009 Valentin Sitdikov <v.sitdikov@gmail.com>
82ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * (C) 2009 Siemens AG
92ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov *
102ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * This program is free software; you can redistribute it and/or modify
112ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * it under the terms of the GNU General Public License version 2 as
122ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * published by the Free Software Foundation.
132ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov *
142ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov */
152ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#include <linux/fb.h>
162ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#include <linux/delay.h>
172ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#include <linux/init.h>
182ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#include <linux/interrupt.h>
19a71dc148c2674bbb5988ea924702137993b3305aRandy Dunlap#include <linux/module.h>
202ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#include <linux/pci.h>
215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
222ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#if defined(CONFIG_OF)
232ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#include <linux/of_platform.h>
242ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#endif
252ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#include "mb862xxfb.h"
262ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#include "mb862xx_reg.h"
272ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#include "mb862xxfb_accel.h"
282ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
292ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikovstatic void mb862xxfb_write_fifo(u32 count, u32 *data, struct fb_info *info)
302ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov{
312ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	struct mb862xxfb_par *par = info->par;
322ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	static u32 free;
332ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
342ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u32 total = 0;
352ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	while (total < count) {
362ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		if (free) {
372ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			outreg(geo, GDC_GEO_REG_INPUT_FIFO, data[total]);
382ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			total++;
392ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			free--;
402ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		} else {
412ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			free = (u32) inreg(draw, GDC_REG_FIFO_COUNT);
422ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		}
432ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	}
442ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov}
452ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
462ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikovstatic void mb86290fb_copyarea(struct fb_info *info,
472ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			       const struct fb_copyarea *area)
482ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov{
492ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	__u32 cmd[6];
502ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
512ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
522ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	/* Set raster operation */
532ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
542ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[2] = GDC_TYPE_BLTCOPYP << 24;
552ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
562ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	if (area->sx >= area->dx && area->sy >= area->dy)
572ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmd[2] |= GDC_CMD_BLTCOPY_TOP_LEFT << 16;
582ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	else if (area->sx >= area->dx && area->sy <= area->dy)
592ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_LEFT << 16;
602ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	else if (area->sx <= area->dx && area->sy >= area->dy)
612ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmd[2] |= GDC_CMD_BLTCOPY_TOP_RIGHT << 16;
622ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	else
632ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_RIGHT << 16;
642ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
652ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[3] = (area->sy << 16) | area->sx;
662ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[4] = (area->dy << 16) | area->dx;
672ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[5] = (area->height << 16) | area->width;
682ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	mb862xxfb_write_fifo(6, cmd, info);
692ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov}
702ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
712ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov/*
722ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * Fill in the cmd array /GDC FIFO commands/ to draw a 1bit image.
732ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * Make sure cmd has enough room!
742ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov */
752ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikovstatic void mb86290fb_imageblit1(u32 *cmd, u16 step, u16 dx, u16 dy,
762ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				 u16 width, u16 height, u32 fgcolor,
772ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				 u32 bgcolor, const struct fb_image *image,
782ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				 struct fb_info *info)
792ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov{
802ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	int i;
812ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	unsigned const char *line;
822ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u16 bytes;
832ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
842ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	/* set colors and raster operation regs */
852ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
862ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	/* Set raster operation */
872ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
882ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[2] =
892ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	    (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16);
902ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[3] = fgcolor;
912ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[4] =
922ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	    (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_BACK_COLOR << 16);
932ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[5] = bgcolor;
942ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
952ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	i = 0;
962ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	line = image->data;
972ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	bytes = (image->width + 7) >> 3;
982ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
992ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	/* and the image */
1002ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[6] = (GDC_TYPE_DRAWBITMAPP << 24) |
1012ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	    (GDC_CMD_BITMAP << 16) | (2 + (step * height));
1022ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[7] = (dy << 16) | dx;
1032ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[8] = (height << 16) | width;
1042ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1052ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	while (i < height) {
1062ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		memcpy(&cmd[9 + i * step], line, step << 2);
1072ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#ifdef __LITTLE_ENDIAN
1082ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		{
1092ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			int k = 0;
1102ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			for (k = 0; k < step; k++)
1112ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				cmd[9 + i * step + k] =
1122ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				    cpu_to_be32(cmd[9 + i * step + k]);
1132ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		}
1142ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov#endif
1152ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		line += bytes;
1162ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		i++;
1172ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	}
1182ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov}
1192ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1202ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov/*
1212ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * Fill in the cmd array /GDC FIFO commands/ to draw a 8bit image.
1222ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * Make sure cmd has enough room!
1232ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov */
1242ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikovstatic void mb86290fb_imageblit8(u32 *cmd, u16 step, u16 dx, u16 dy,
1252ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				 u16 width, u16 height, u32 fgcolor,
1262ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				 u32 bgcolor, const struct fb_image *image,
1272ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				 struct fb_info *info)
1282ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov{
1292ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	int i, j;
1302ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	unsigned const char *line, *ptr;
1312ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u16 bytes;
1322ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1332ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) |
1342ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	    (GDC_CMD_BLT_DRAW << 16) | (2 + (height * step));
1352ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[1] = (dy << 16) | dx;
1362ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[2] = (height << 16) | width;
1372ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1382ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	i = 0;
1392ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	line = ptr = image->data;
1402ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	bytes = image->width;
1412ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1422ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	while (i < height) {
1432ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		ptr = line;
1442ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		for (j = 0; j < step; j++) {
1452ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			cmd[3 + i * step + j] =
1462ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			    (((u32 *) (info->pseudo_palette))[*ptr]) & 0xffff;
1472ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			ptr++;
1482ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			cmd[3 + i * step + j] |=
1492ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			    ((((u32 *) (info->
1502ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov					pseudo_palette))[*ptr]) & 0xffff) << 16;
1512ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			ptr++;
1522ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		}
1532ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1542ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		line += bytes;
1552ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		i++;
1562ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	}
1572ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov}
1582ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1592ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov/*
1602ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * Fill in the cmd array /GDC FIFO commands/ to draw a 16bit image.
1612ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov * Make sure cmd has enough room!
1622ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov */
1632ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikovstatic void mb86290fb_imageblit16(u32 *cmd, u16 step, u16 dx, u16 dy,
1642ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				  u16 width, u16 height, u32 fgcolor,
1652ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				  u32 bgcolor, const struct fb_image *image,
1662ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				  struct fb_info *info)
1672ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov{
1682ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	int i;
1692ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	unsigned const char *line;
1702ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u16 bytes;
1712ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1722ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	i = 0;
1732ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	line = image->data;
1742ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	bytes = image->width << 1;
1752ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1762ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) |
1772ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	    (GDC_CMD_BLT_DRAW << 16) | (2 + step * height);
1782ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[1] = (dy << 16) | dx;
1792ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[2] = (height << 16) | width;
1802ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1812ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	while (i < height) {
1822ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		memcpy(&cmd[3 + i * step], line, step);
1832ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		line += bytes;
1842ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		i++;
1852ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	}
1862ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov}
1872ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1882ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikovstatic void mb86290fb_imageblit(struct fb_info *info,
1892ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov				const struct fb_image *image)
1902ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov{
1912ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	int mdr;
1922ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u32 *cmd = NULL;
1932ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	void (*cmdfn) (u32 *, u16, u16, u16, u16, u16, u32, u32,
1942ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		       const struct fb_image *, struct fb_info *) = NULL;
1952ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u32 cmdlen;
1962ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u32 fgcolor = 0, bgcolor = 0;
1972ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u16 step;
1982ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
1992ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u16 width = image->width, height = image->height;
2002ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u16 dx = image->dx, dy = image->dy;
2012ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	int x2, y2, vxres, vyres;
2022ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2032ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	mdr = (GDC_ROP_COPY << 9);
2042ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	x2 = image->dx + image->width;
2052ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	y2 = image->dy + image->height;
2062ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	vxres = info->var.xres_virtual;
2072ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	vyres = info->var.yres_virtual;
2082ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	x2 = min(x2, vxres);
2092ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	y2 = min(y2, vyres);
2102ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	width = x2 - dx;
2112ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	height = y2 - dy;
2122ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2132ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	switch (image->depth) {
2142ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	case 1:
2152ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		step = (width + 31) >> 5;
2162ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmdlen = 9 + height * step;
2172ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmdfn = mb86290fb_imageblit1;
2182ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
2192ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
2202ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			fgcolor =
2212ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			    ((u32 *) (info->pseudo_palette))[image->fg_color];
2222ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			bgcolor =
2232ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			    ((u32 *) (info->pseudo_palette))[image->bg_color];
2242ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		} else {
2252ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			fgcolor = image->fg_color;
2262ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			bgcolor = image->bg_color;
2272ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		}
2282ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2292ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		break;
2302ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2312ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	case 8:
2322ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		step = (width + 1) >> 1;
2332ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmdlen = 3 + height * step;
2342ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmdfn = mb86290fb_imageblit8;
2352ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		break;
2362ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2372ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	case 16:
2382ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		step = (width + 1) >> 1;
2392ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmdlen = 3 + height * step;
2402ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmdfn = mb86290fb_imageblit16;
2412ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		break;
2422ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2432ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	default:
2442ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cfb_imageblit(info, image);
2452ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		return;
2462ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	}
2472ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2482ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd = kmalloc(cmdlen * 4, GFP_DMA);
2492ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	if (!cmd)
2502ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		return cfb_imageblit(info, image);
2512ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmdfn(cmd, step, dx, dy, width, height, fgcolor, bgcolor, image, info);
2522ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	mb862xxfb_write_fifo(cmdlen, cmd, info);
2532ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	kfree(cmd);
2542ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov}
2552ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2562ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikovstatic void mb86290fb_fillrect(struct fb_info *info,
2572ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov			       const struct fb_fillrect *rect)
2582ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov{
2592ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2602ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u32 x2, y2, vxres, vyres, height, width, fg;
2612ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	u32 cmd[7];
2622ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2632ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	vxres = info->var.xres_virtual;
2642ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	vyres = info->var.yres_virtual;
2652ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2662ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	if (!rect->width || !rect->height || rect->dx > vxres
2672ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	    || rect->dy > vyres)
2682ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		return;
2692ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2702ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	/* We could use hardware clipping but on many cards you get around
2712ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	 * hardware clipping by writing to framebuffer directly. */
2722ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	x2 = rect->dx + rect->width;
2732ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	y2 = rect->dy + rect->height;
2742ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	x2 = min(x2, vxres);
2752ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	y2 = min(y2, vyres);
2762ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	width = x2 - rect->dx;
2772ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	height = y2 - rect->dy;
2782ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
2792ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	    info->fix.visual == FB_VISUAL_DIRECTCOLOR)
2802ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		fg = ((u32 *) (info->pseudo_palette))[rect->color];
2812ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	else
2822ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		fg = rect->color;
2832ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2842ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	switch (rect->rop) {
2852ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2862ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	case ROP_XOR:
2872ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		/* Set raster operation */
2882ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmd[1] = (2 << 7) | (GDC_ROP_XOR << 9);
2892ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		break;
2902ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2912ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	case ROP_COPY:
2922ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		/* Set raster operation */
2932ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
2942ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		break;
2952ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2962ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	}
2972ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
2982ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
2992ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	/* cmd[1] set earlier */
3002ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[2] =
3012ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	    (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16);
3022ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[3] = fg;
3032ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[4] = (GDC_TYPE_DRAWRECTP << 24) | (GDC_CMD_BLT_FILL << 16);
3042ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[5] = (rect->dy << 16) | (rect->dx);
3052ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	cmd[6] = (height << 16) | width;
3062ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
3072ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	mb862xxfb_write_fifo(7, cmd, info);
3082ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov}
3092ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
3102ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikovvoid mb862xxfb_init_accel(struct fb_info *info, int xres)
3112ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov{
3122ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	struct mb862xxfb_par *par = info->par;
3132ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
3142ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	if (info->var.bits_per_pixel == 32) {
3152ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		info->fbops->fb_fillrect = cfb_fillrect;
3162ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		info->fbops->fb_copyarea = cfb_copyarea;
3172ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		info->fbops->fb_imageblit = cfb_imageblit;
3182ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	} else {
3192ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		outreg(disp, GC_L0EM, 3);
3202ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		info->fbops->fb_fillrect = mb86290fb_fillrect;
3212ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		info->fbops->fb_copyarea = mb86290fb_copyarea;
3222ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov		info->fbops->fb_imageblit = mb86290fb_imageblit;
3232ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	}
3242ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	outreg(draw, GDC_REG_DRAW_BASE, 0);
3252ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	outreg(draw, GDC_REG_MODE_MISC, 0x8000);
3262ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	outreg(draw, GDC_REG_X_RESOLUTION, xres);
3272ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov
3282ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	info->flags |=
3292ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	    FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
3302ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	    FBINFO_HWACCEL_IMAGEBLIT;
3312ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov	info->fix.accel = 0xff;	/*FIXME: add right define */
3322ec509b96cce5e6d19ee43fdd818eab78e76328dValentin Sitdikov}
3332ec509b96cce5e6d19ee43fdd818eab78e76328dValentin SitdikovEXPORT_SYMBOL(mb862xxfb_init_accel);
334a71dc148c2674bbb5988ea924702137993b3305aRandy Dunlap
335a71dc148c2674bbb5988ea924702137993b3305aRandy DunlapMODULE_LICENSE("GPL v2");
336