wmt_ge_rops.c 5.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
/*
 *  linux/drivers/video/wmt_ge_rops.c
 *
 *  Accelerators for raster operations using WonderMedia Graphics Engine
 *
 *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/module.h>
#include <linux/fb.h>
#include <linux/platform_device.h>
#include "fb_draw.h"

#define GE_COMMAND_OFF		0x00
#define GE_DEPTH_OFF		0x04
#define GE_HIGHCOLOR_OFF	0x08
#define GE_ROPCODE_OFF		0x14
#define GE_FIRE_OFF		0x18
#define GE_SRCBASE_OFF		0x20
#define GE_SRCDISPW_OFF		0x24
#define GE_SRCDISPH_OFF		0x28
#define GE_SRCAREAX_OFF		0x2c
#define GE_SRCAREAY_OFF		0x30
#define GE_SRCAREAW_OFF		0x34
#define GE_SRCAREAH_OFF		0x38
#define GE_DESTBASE_OFF		0x3c
#define GE_DESTDISPW_OFF	0x40
#define GE_DESTDISPH_OFF	0x44
#define GE_DESTAREAX_OFF	0x48
#define GE_DESTAREAY_OFF	0x4c
#define GE_DESTAREAW_OFF	0x50
#define GE_DESTAREAH_OFF	0x54
#define GE_PAT0C_OFF		0x88	/* Pattern 0 color */
#define GE_ENABLE_OFF		0xec
#define GE_INTEN_OFF		0xf0
#define GE_STATUS_OFF		0xf8

static void __iomem *regbase;

void wmt_ge_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
{
	unsigned long fg, pat;

	if (p->state != FBINFO_STATE_RUNNING)
		return;

	if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
	    p->fix.visual == FB_VISUAL_DIRECTCOLOR)
		fg = ((u32 *) (p->pseudo_palette))[rect->color];
	else
		fg = rect->color;

	pat = pixel_to_pat(p->var.bits_per_pixel, fg);

	if (p->fbops->fb_sync)
		p->fbops->fb_sync(p);

	writel(p->var.bits_per_pixel == 32 ? 3 :
	      (p->var.bits_per_pixel == 8 ? 0 : 1), regbase + GE_DEPTH_OFF);
	writel(p->var.bits_per_pixel == 15 ? 1 : 0, regbase + GE_HIGHCOLOR_OFF);
	writel(p->fix.smem_start, regbase + GE_DESTBASE_OFF);
	writel(p->var.xres_virtual - 1, regbase + GE_DESTDISPW_OFF);
	writel(p->var.yres_virtual - 1, regbase + GE_DESTDISPH_OFF);
	writel(rect->dx, regbase + GE_DESTAREAX_OFF);
	writel(rect->dy, regbase + GE_DESTAREAY_OFF);
	writel(rect->width - 1, regbase + GE_DESTAREAW_OFF);
	writel(rect->height - 1, regbase + GE_DESTAREAH_OFF);

	writel(pat, regbase + GE_PAT0C_OFF);
	writel(1, regbase + GE_COMMAND_OFF);
	writel(rect->rop == ROP_XOR ? 0x5a : 0xf0, regbase + GE_ROPCODE_OFF);
	writel(1, regbase + GE_FIRE_OFF);
}
EXPORT_SYMBOL_GPL(wmt_ge_fillrect);

void wmt_ge_copyarea(struct fb_info *p, const struct fb_copyarea *area)
{
	if (p->state != FBINFO_STATE_RUNNING)
		return;

	if (p->fbops->fb_sync)
		p->fbops->fb_sync(p);

	writel(p->var.bits_per_pixel > 16 ? 3 :
	      (p->var.bits_per_pixel > 8 ? 1 : 0), regbase + GE_DEPTH_OFF);

	writel(p->fix.smem_start, regbase + GE_SRCBASE_OFF);
	writel(p->var.xres_virtual - 1, regbase + GE_SRCDISPW_OFF);
	writel(p->var.yres_virtual - 1, regbase + GE_SRCDISPH_OFF);
	writel(area->sx, regbase + GE_SRCAREAX_OFF);
	writel(area->sy, regbase + GE_SRCAREAY_OFF);
	writel(area->width - 1, regbase + GE_SRCAREAW_OFF);
	writel(area->height - 1, regbase + GE_SRCAREAH_OFF);

	writel(p->fix.smem_start, regbase + GE_DESTBASE_OFF);
	writel(p->var.xres_virtual - 1, regbase + GE_DESTDISPW_OFF);
	writel(p->var.yres_virtual - 1, regbase + GE_DESTDISPH_OFF);
	writel(area->dx, regbase + GE_DESTAREAX_OFF);
	writel(area->dy, regbase + GE_DESTAREAY_OFF);
	writel(area->width - 1, regbase + GE_DESTAREAW_OFF);
	writel(area->height - 1, regbase + GE_DESTAREAH_OFF);

	writel(0xcc, regbase + GE_ROPCODE_OFF);
	writel(1, regbase + GE_COMMAND_OFF);
	writel(1, regbase + GE_FIRE_OFF);
}
EXPORT_SYMBOL_GPL(wmt_ge_copyarea);

int wmt_ge_sync(struct fb_info *p)
{
	int loops = 5000000;
	while ((readl(regbase + GE_STATUS_OFF) & 4) && --loops)
		cpu_relax();
	return loops > 0 ? 0 : -EBUSY;
}
EXPORT_SYMBOL_GPL(wmt_ge_sync);

static int __devinit wmt_ge_rops_probe(struct platform_device *pdev)
{
	struct resource *res;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL) {
		dev_err(&pdev->dev, "no I/O memory resource defined\n");
134
		return -ENODEV;
135 136 137 138 139 140 141 142 143 144 145
	}

	/* Only one ROP engine is presently supported. */
	if (unlikely(regbase)) {
		WARN_ON(1);
		return -EBUSY;
	}

	regbase = ioremap(res->start, resource_size(res));
	if (regbase == NULL) {
		dev_err(&pdev->dev, "failed to map I/O memory\n");
146
		return -EBUSY;
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
	}

	writel(1, regbase + GE_ENABLE_OFF);
	printk(KERN_INFO "Enabled support for WMT GE raster acceleration\n");

	return 0;
}

static int __devexit wmt_ge_rops_remove(struct platform_device *pdev)
{
	iounmap(regbase);
	return 0;
}

static struct platform_driver wmt_ge_rops_driver = {
	.probe		= wmt_ge_rops_probe,
	.remove		= __devexit_p(wmt_ge_rops_remove),
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "wmt_ge_rops",
	},
};

static int __init wmt_ge_rops_init(void)
{
	return platform_driver_register(&wmt_ge_rops_driver);
}

static void __exit wmt_ge_rops_exit(void)
{
	platform_driver_unregister(&wmt_ge_rops_driver);
}

module_init(wmt_ge_rops_init);
module_exit(wmt_ge_rops_exit);

MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com");
MODULE_DESCRIPTION("Accelerators for raster operations using "
		   "WonderMedia Graphics Engine");
MODULE_LICENSE("GPL");