11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/video/q40fb.c -- Q40 frame buffer device
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Richard Zidlicky <rz@linux-m68k.org>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This file is subject to the terms and conditions of the GNU General Public
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  License. See the file COPYING in the main directory of this archive for
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  more details.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
19d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/setup.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/q40_master.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fb.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Q40_PHYS_SCREEN_ADDR 0xFE800000
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3048c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic struct fb_fix_screeninfo q40fb_fix = {
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id		= "Q40",
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.smem_len	= 1024*1024,
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.type		= FB_TYPE_PACKED_PIXELS,
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.visual		= FB_VISUAL_TRUECOLOR,
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.line_length	= 1024*2,
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.accel		= FB_ACCEL_NONE,
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3948c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic struct fb_var_screeninfo q40fb_var = {
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 1024,
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres		= 512,
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres_virtual	= 1024,
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres_virtual	= 512,
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.bits_per_pixel	= 16,
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    	.red		= {6, 5, 0},
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.green		= {11, 5, 0},
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.blue		= {0, 6, 0},
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.activate	= FB_ACTIVATE_NOW,
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.height		= 230,
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.width		= 300,
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vmode		= FB_VMODE_NONINTERLACED,
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   unsigned blue, unsigned transp,
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct fb_info *info)
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /*
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     *  Set a single color register. The values supplied have a 16 bit
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     *  magnitude.
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     *  Return != 0 for invalid regno.
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (regno > 255)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    return 1;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    red>>=11;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    green>>=11;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    blue>>=10;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (regno < 16) {
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	((u32 *)info->pseudo_palette)[regno] = ((red & 31) <<6) |
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       ((green & 31) << 11) |
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       (blue & 63);
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return 0;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fb_ops q40fb_ops = {
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_setcolreg	= q40fb_setcolreg,
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_fillrect	= cfb_fillrect,
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_copyarea	= cfb_copyarea,
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_imageblit	= cfb_imageblit,
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8648c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int q40fb_probe(struct platform_device *dev)
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fb_info *info;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!MACH_IS_Q40)
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* mapped in q40/config.c */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
96ce303c076baad1b7d8d41d1b98c373843eb820ccAntonino A. Daplas	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->var = q40fb_var;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->fix = q40fb_fix;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->fbops = &q40fb_ops;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->flags = FBINFO_DEFAULT;  /* not as module for now */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->pseudo_palette = info->par;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->par = NULL;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->screen_base = (char *) q40fb_fix.smem_start;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		framebuffer_release(info);
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	master_outb(3, DISPLAY_CONTROL_REG);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (register_framebuffer(info) < 0) {
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Unable to register Q40 frame buffer\n");
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fb_dealloc_cmap(&info->cmap);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		framebuffer_release(info);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12231b6780c15a4e3a90fe260e977f5186772ce7afbJoe Perches	fb_info(info, "Q40 frame buffer alive and kicking !\n");
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1263ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver q40fb_driver = {
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe	= q40fb_probe,
1283ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver	= {
1293ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= "q40fb",
1303ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct platform_device q40fb_device = {
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name	= "q40fb",
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init q40fb_init(void)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fb_get_options("q40fb", NULL))
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1443ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	ret = platform_driver_register(&q40fb_driver);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ret) {
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = platform_device_register(&q40fb_device);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret)
1493ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King			platform_driver_unregister(&q40fb_driver);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(q40fb_init);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
156