summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/q40fb.c
blob: 079a2a7fb2c58a23ad365ad8e32651ad8ac3dcca (plain)
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * linux/drivers/video/q40fb.c -- Q40 frame buffer device
 *
 * Copyright (C) 2001
 *
 *      Richard Zidlicky <rz@linux-m68k.org>
 *
 *  This file is subject to the terms and conditions of the GNU General Public
 *  License. See the file COPYING in the main directory of this archive for
 *  more details.
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>

#include <linux/uaccess.h>
#include <asm/setup.h>
#include <asm/q40_master.h>
#include <linux/fb.h>
#include <linux/module.h>

#define Q40_PHYS_SCREEN_ADDR 0xFE800000

static struct fb_fix_screeninfo q40fb_fix = {
	.id		= "Q40",
	.smem_len	= 1024*1024,
	.type		= FB_TYPE_PACKED_PIXELS,
	.visual		= FB_VISUAL_TRUECOLOR,
	.line_length	= 1024*2,
	.accel		= FB_ACCEL_NONE,
};

static const struct fb_var_screeninfo q40fb_var = {
	.xres		= 1024,
	.yres		= 512,
	.xres_virtual	= 1024,
	.yres_virtual	= 512,
	.bits_per_pixel	= 16,
    	.red		= {6, 5, 0},
	.green		= {11, 5, 0},
	.blue		= {0, 6, 0},
	.activate	= FB_ACTIVATE_NOW,
	.height		= 230,
	.width		= 300,
	.vmode		= FB_VMODE_NONINTERLACED,
};

static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
			   unsigned blue, unsigned transp,
			   struct fb_info *info)
{
    /*
     *  Set a single color register. The values supplied have a 16 bit
     *  magnitude.
     *  Return != 0 for invalid regno.
     */

    if (regno > 255)
	    return 1;
    red>>=11;
    green>>=11;
    blue>>=10;

    if (regno < 16) {
	((u32 *)info->pseudo_palette)[regno] = ((red & 31) <<6) |
					       ((green & 31) << 11) |
					       (blue & 63);
    }
    return 0;
}

static const struct fb_ops q40fb_ops = {
	.owner		= THIS_MODULE,
	.fb_setcolreg	= q40fb_setcolreg,
	.fb_fillrect	= cfb_fillrect,
	.fb_copyarea	= cfb_copyarea,
	.fb_imageblit	= cfb_imageblit,
};

static int q40fb_probe(struct platform_device *dev)
{
	struct fb_info *info;

	if (!MACH_IS_Q40)
		return -ENXIO;

	/* mapped in q40/config.c */
	q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR;

	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
	if (!info)
		return -ENOMEM;

	info->var = q40fb_var;
	info->fix = q40fb_fix;
	info->fbops = &q40fb_ops;
	info->flags = FBINFO_DEFAULT;  /* not as module for now */
	info->pseudo_palette = info->par;
	info->par = NULL;
	info->screen_base = (char *) q40fb_fix.smem_start;

	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
		framebuffer_release(info);
		return -ENOMEM;
	}

	master_outb(3, DISPLAY_CONTROL_REG);

	if (register_framebuffer(info) < 0) {
		printk(KERN_ERR "Unable to register Q40 frame buffer\n");
		fb_dealloc_cmap(&info->cmap);
		framebuffer_release(info);
		return -EINVAL;
	}

	fb_info(info, "Q40 frame buffer alive and kicking !\n");
	return 0;
}

static struct platform_driver q40fb_driver = {
	.probe	= q40fb_probe,
	.driver	= {
		.name	= "q40fb",
	},
};

static struct platform_device q40fb_device = {
	.name	= "q40fb",
};

int __init q40fb_init(void)
{
	int ret = 0;

	if (fb_get_options("q40fb", NULL))
		return -ENODEV;

	ret = platform_driver_register(&q40fb_driver);

	if (!ret) {
		ret = platform_device_register(&q40fb_device);
		if (ret)
			platform_driver_unregister(&q40fb_driver);
	}
	return ret;
}

module_init(q40fb_init);
MODULE_LICENSE("GPL");