sync hh.org
[hh.org.git] / drivers / video / mq1100fb.c
blob6d348a891a17508b467b02a8e156354802056dee
1 /*
2 * linux/drivers/mq1100fb.c
4 * Copyright © 2003 Keith Packard
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
8 * more details.
10 * MediaQ 1100/32/68/78/88 LCD Controller Frame Buffer Driver
12 * Please direct your questions and comments on this driver to the following
13 * email address:
15 * keithp@keithp.com
17 * ChangeLog
19 * 2003-12-06: Andrew Zabolotny <zap@homelink.ru>
20 * - Modified to use the MediaQ SoC base driver to allow
21 * sharing of other MediaQ subdevices with other drivers.
22 * 2003-05-18: <keithp@keithp.com>
23 * - Ported from PCI development board to ARM H5400
26 #include <linux/module.h>
27 #include <linux/kernel.h>
28 #include <linux/errno.h>
29 #include <linux/string.h>
30 #include <linux/fb.h>
31 #include <linux/init.h>
32 #include <linux/platform_device.h>
33 #include <linux/soc-old.h>
34 #include <linux/notifier.h>
35 #include <../drivers/soc/mq11xx.h>
37 #include "console/fbcon.h"
39 #if 0
40 # define debug(s, args...) printk (KERN_INFO s, ##args)
41 #else
42 # define debug(s, args...)
43 #endif
44 #define debug_func(s, args...) debug ("%s: " s, __FUNCTION__, ##args)
46 #define MQ_Rotate_0 1
47 #define MQ_Rotate_90 2
48 #define MQ_Rotate_180 4
49 #define MQ_Rotate_270 8
51 #define MQ_Reflect_X 16
52 #define MQ_Reflect_Y 32
54 struct mq1100fb_rgb {
55 unsigned char red,green,blue,transp;
58 struct mq1100fb_info {
59 /* Framebuffer info */
60 struct fb_info fb;
61 /* The link to the base SoC driver */
62 struct mediaq11xx_base *base;
63 /* The RGB palette */
64 struct mq1100fb_rgb palette[256];
65 /* Notifier block */
66 struct notifier_block notify;
67 /* Framebuffer offset inside MediaQ RAM */
68 u32 fb_addr, fb_size;
69 /* The pseudo-palette */
70 u32 pseudo_pal[16];
71 /* Device instance number (0-7) */
72 u8 inst;
73 /* Combination of MQ_Rotate_XXX bits */
74 u8 rotation;
75 /* 1 if device is active, 0 if poweroff */
76 unsigned active:1;
77 /* 1 if initialization is complete, 0 while it is deferred */
78 unsigned initcomplete:1;
79 /* 1 if power is enabled to the MEDIAQ_11XX_FB_DEVICE_ID subdevice */
80 unsigned poweron:1;
82 #define to_mq1100fb_info(n) container_of(n, struct mq1100fb_info, fb)
84 #define MAX_MQFB_INSTANCES 8
86 static int ppm [MAX_MQFB_INSTANCES];
87 module_param_array(ppm, int, MAX_MQFB_INSTANCES, S_IRUGO);
88 MODULE_PARM_DESC(ppm, "LCD pixel density in pixels per meter");
90 /* ------------------- chipset specific functions -------------------------- */
92 static void mq1100fb_power (struct mq1100fb_info *info, int val)
94 debug_func ("val:%d\n", val);
96 info->active = (val == 0) ? 1 : 0;
98 if (info->active != info->poweron) {
99 info->poweron = info->active;
100 info->base->set_power (info->base, MEDIAQ_11XX_FB_DEVICE_ID,
101 info->active);
105 static void mq1100fb_update_screeninfo (struct mq1100fb_info *info, int ppm)
107 u32 control = info->base->regs->GC.control;
108 u32 horizontal_width = info->base->regs->GC.horizontal_window;
109 u32 vertical_height = info->base->regs->GC.vertical_window;
110 u32 window_stride = info->base->regs->GC.window_stride;
111 int stride;
113 debug_func ("ppm:%d\n", ppm);
115 info->fb.var.grayscale = 0;
117 switch (control & MQ_GC_DEPTH) {
118 case MQ_GC_DEPTH_PSEUDO_1:
119 info->fb.var.bits_per_pixel = 1;
120 info->fb.fix.visual = FB_VISUAL_MONO01;
121 break;
122 case MQ_GC_DEPTH_PSEUDO_2:
123 info->fb.var.bits_per_pixel = 2;
124 info->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
125 break;
126 case MQ_GC_DEPTH_PSEUDO_4:
127 info->fb.var.bits_per_pixel = 4;
128 info->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
129 break;
130 case MQ_GC_DEPTH_PSEUDO_8:
131 info->fb.var.bits_per_pixel = 8;
132 info->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
133 break;
134 case MQ_GC_DEPTH_GRAY_1:
135 info->fb.var.bits_per_pixel = 1;
136 info->fb.var.grayscale = 1;
137 info->fb.fix.visual = FB_VISUAL_MONO01;
138 break;
139 case MQ_GC_DEPTH_GRAY_2:
140 info->fb.var.bits_per_pixel = 2;
141 info->fb.var.grayscale = 1;
142 info->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
143 break;
144 case MQ_GC_DEPTH_GRAY_4:
145 info->fb.var.bits_per_pixel = 4;
146 info->fb.var.grayscale = 1;
147 info->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
148 break;
149 case MQ_GC_DEPTH_GRAY_8:
150 info->fb.var.bits_per_pixel = 8;
151 info->fb.var.grayscale = 1;
152 info->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
153 break;
154 case MQ_GC_DEPTH_TRUE_16:
155 info->fb.var.bits_per_pixel = 16;
156 info->fb.fix.visual = FB_VISUAL_TRUECOLOR;
157 break;
160 info->fb.var.xres = info->fb.var.xres_virtual =
161 ((horizontal_width & MQ_GC_HORIZONTAL_WINDOW_WIDTH) >> 16) + 1;
162 info->fb.var.yres = info->fb.var.yres_virtual =
163 ((vertical_height & MQ_GC_VERTICAL_WINDOW_HEIGHT) >> 16) + 1;
164 stride = (short)window_stride;
165 info->fb.fix.line_length = (stride < 0) ? -stride : stride;
167 switch (control & (MQ_GC_X_SCANNING_DIRECTION|MQ_GC_LINE_SCANNING_DIRECTION)) {
168 case 0:
169 if (stride >= 0)
170 info->rotation = MQ_Rotate_0; /* 000 */
171 else
172 info->rotation |= MQ_Rotate_0 | MQ_Reflect_Y; /* 010 */
173 break;
174 case MQ_GC_X_SCANNING_DIRECTION:
175 if (stride >= 0)
176 info->rotation = MQ_Rotate_0 | MQ_Reflect_X; /* 001 */
177 else
178 info->rotation = MQ_Rotate_180; /* 011 */
179 break;
180 case MQ_GC_LINE_SCANNING_DIRECTION:
181 if (stride >= 0)
182 info->rotation = MQ_Rotate_90 | MQ_Reflect_X; /* 100 */
183 else
184 info->rotation = MQ_Rotate_90; /* 110 */
185 break;
186 case MQ_GC_LINE_SCANNING_DIRECTION|MQ_GC_X_SCANNING_DIRECTION:
187 if (stride >= 0)
188 info->rotation = MQ_Rotate_270; /* 101 */
189 else
190 info->rotation = MQ_Rotate_270 | MQ_Reflect_X; /* 111 */
191 break;
194 info->fb.var.width = info->fb.var.xres * 1000 / ppm;
195 info->fb.var.height = info->fb.var.yres * 1000 / ppm;
199 * mq1100fb_check_var():
200 * Round up in the following order: bits_per_pixel, xres,
201 * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
202 * bitfields, horizontal timing, vertical timing.
204 static int mq1100fb_check_var(struct fb_var_screeninfo *var,
205 struct fb_info *fbinfo)
207 debug_func ("\n");
209 switch (var->bits_per_pixel) {
210 case 8:
211 var->red.offset = 0;
212 var->green.offset = 0;
213 var->blue.offset = 0;
214 var->red.length = 6;
215 var->green.length = 6;
216 var->blue.length = 6;
217 break;
218 case 16:
219 var->red.offset = 11;
220 var->green.offset = 5;
221 var->blue.offset = 0;
222 var->red.length = 5;
223 var->green.length = 6;
224 var->blue.length = 5;
225 break;
226 default:
227 return -EINVAL;
230 return 0;
233 static int mq1100fb_set_par(struct fb_info *fbinfo)
235 struct mq1100fb_info *info = to_mq1100fb_info(fbinfo);
237 debug_func ("\n");
239 if (!info->active)
240 /* Enable the LCD controller */
241 mq1100fb_power (info, 0);
243 return 0;
246 static int mq1100fb_setcolreg(unsigned regno, unsigned red, unsigned green,
247 unsigned blue, unsigned transp,
248 struct fb_info *fbinfo)
250 struct mq1100fb_info *info = to_mq1100fb_info(fbinfo);
251 int bpp, m = 0;
253 debug_func ("color:%d rgba:%d/%d/%d/%d\n",
254 regno, red>>8, green>>8, blue>>8, transp>>8);
256 bpp = info->fb.var.bits_per_pixel;
257 m = (bpp <= 8) ? (1 << bpp) : 256;
258 if (regno >= m) {
259 debug ("regno %d out of range (max %d)\n", regno, m);
260 return -EINVAL;
263 info->palette[regno].red = red;
264 info->palette[regno].green = green;
265 info->palette[regno].blue = blue;
266 info->palette[regno].transp = transp;
268 switch (bpp) {
269 case 8:
270 break;
271 case 16:
272 /* RGB 565 */
273 info->pseudo_pal[regno] = ((red & 0xF800) |
274 ((green & 0xFC00) >> 5) |
275 ((blue & 0xF800) >> 11));
276 break;
279 return 0;
282 static int mq1100fb_pan_display(struct fb_var_screeninfo *var,
283 struct fb_info *fbinfo)
285 debug_func ("\n");
287 * Pan (or wrap, depending on the `vmode' field) the display using the
288 * `xoffset' and `yoffset' fields of the `var' structure.
289 * If the values don't fit, return -EINVAL.
292 /* ... */
293 return 0;
296 static void mq1100fb_rotate (struct fb_info *fbinfo, int angle)
298 /* For now it is not implemented but mq1100 fully
299 * supports display rotation.
301 debug_func ("\n");
304 static int mq1100fb_blank(int blank_mode, struct fb_info *fbinfo)
306 struct mq1100fb_info *info = to_mq1100fb_info(fbinfo);
308 debug_func ("blank_mode:%d\n", blank_mode);
311 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
312 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
313 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
314 * to e.g. a video mode which doesn't support it. Implements VESA suspend
315 * and powerdown modes on hardware that supports disabling hsync/vsync:
316 * blank_mode == 2: suspend vsync
317 * blank_mode == 3: suspend hsync
318 * blank_mode == 4: powerdown
321 mq1100fb_power (info, blank_mode);
323 return 0;
326 /* ------------ Interfaces to hardware functions ------------ */
328 static struct fb_ops mq1100fb_ops = {
329 .owner = THIS_MODULE,
330 .fb_check_var = mq1100fb_check_var,
331 .fb_set_par = mq1100fb_set_par,
332 .fb_setcolreg = mq1100fb_setcolreg,
333 .fb_fillrect = cfb_fillrect,
334 .fb_copyarea = cfb_copyarea,
335 .fb_imageblit = cfb_imageblit,
336 .fb_blank = mq1100fb_blank,
337 .fb_pan_display = mq1100fb_pan_display,
338 .fb_rotate = mq1100fb_rotate,
339 #ifdef CONFIG_FB_SOFT_CURSOR
340 .fb_cursor = soft_cursor
341 #endif
344 static struct fb_bitfield def_rgb [3] = {
345 { 11, 5, 0 }, /* red */
346 { 5, 6, 0 }, /* green */
347 { 0, 5, 0 }, /* blue */
350 static int mq1100fb_finish_init (struct mq1100fb_info *info)
352 int err;
353 int inst_ppm = ppm [info->inst];
354 if (!inst_ppm)
355 inst_ppm = 4210;
357 debug_func ("\n");
359 info->fb.var.red = def_rgb [0];
360 info->fb.var.green = def_rgb [1];
361 info->fb.var.blue = def_rgb [2];
362 info->fb.var.activate = FB_ACTIVATE_NOW;
364 strcpy (info->fb.fix.id, "mq1100");
365 info->fb.fix.type = FB_TYPE_PACKED_PIXELS;
366 info->fb.fix.type_aux = 0;
367 info->fb.fix.xpanstep = info->fb.fix.ypanstep = 0;
368 info->fb.fix.ywrapstep = 0;
369 info->fb.fix.accel = FB_ACCEL_NONE;
371 info->fb.screen_base = info->base->gfxram;
372 info->fb.pseudo_palette = &info->pseudo_pal;
373 info->fb.fbops = &mq1100fb_ops;
375 mq1100fb_update_screeninfo (info, inst_ppm);
377 info->fb_size = info->fb.fix.line_length * info->fb.var.yres_virtual;
378 info->fb_addr = info->base->alloc (info->base, info->fb_size, 1);
380 if (info->fb_addr == (u32)-1) {
381 err = -ENOMEM;
382 printk (KERN_ERR "Cannot allocate %u bytes in MediaQ internal RAM for framebuffer\n",
383 info->fb_size);
384 error: kfree (info);
385 return err;
388 //info->fb.fix.mmio_start = info->base->paddr_regs;
389 //info->fb.fix.mmio_len = MQ11xx_REG_SIZE;
390 info->fb.fix.smem_start = info->base->paddr_gfxram + info->fb_addr;
391 info->fb.fix.smem_len = info->fb_size;
393 /* Program framebuffer start address */
394 info->base->regs->GC.window_start_address = info->fb_addr;
396 if ((err = register_framebuffer(&info->fb)) < 0) {
397 printk (KERN_ERR "Could not register mq1100 framebuffer\n");
398 info->base->free (info->base, info->fb_addr, info->fb_size);
399 goto error;
402 info->initcomplete = 1;
404 /* Clear the screen in the case we don't use fbcon */
405 memset (info->base->gfxram + info->fb_addr, 0, info->fb_size);
407 debug ("frame buffer device %dx%d-%dbpp\n",
408 info->fb.var.xres, info->fb.var.yres, info->fb.var.bits_per_pixel);
409 return 0;
412 static int mq1100fb_probe (struct device *dev, struct mediaq11xx_base *base)
414 struct platform_device *pdev = to_platform_device(dev);
415 struct mq1100fb_info *info;
417 info = kmalloc (sizeof (struct mq1100fb_info), GFP_KERNEL);
418 memset (info, 0, sizeof (struct mq1100fb_info));
419 info->base = base;
420 info->inst = pdev->id;
422 dev_set_drvdata (dev, info);
424 /* Turn on the power to the MediaQ chip */
425 mq1100fb_power (info, 0);
426 mq1100fb_finish_init (info);
428 return 0;
431 static int mq1100fb_platform_probe (struct device *dev)
433 debug_func ("\n");
434 return mq1100fb_probe (dev, (struct mediaq11xx_base *)dev->platform_data);
437 static int mq1100fb_platform_remove (struct device *dev)
439 struct mq1100fb_info *info =
440 (struct mq1100fb_info *)dev_get_drvdata (dev);
442 debug_func ("\n");
444 if (info->active) {
445 mq1100fb_power (info, 4);
446 unregister_framebuffer (&info->fb);
447 info->base->free (info->base, info->fb_addr, info->fb_size);
450 return 0;
453 static int mq1100fb_platform_suspend (struct device *dev, pm_message_t state)
455 struct mq1100fb_info *info =
456 (struct mq1100fb_info *)dev_get_drvdata (dev);
458 debug_func ("\n");
460 mq1100fb_power (info, 4);
462 return 0;
465 static int mq1100fb_platform_resume (struct device *dev)
467 struct mq1100fb_info *info =
468 (struct mq1100fb_info *)dev_get_drvdata (dev);
470 debug_func ("\n");
472 mq1100fb_power (info, 0);
474 return 0;
477 /* We need the framebuffer subdevice */
478 struct device_driver mq1100fb_device_driver = {
479 .name = "mq11xx_fb",
480 .bus = &platform_bus_type,
481 .probe = mq1100fb_platform_probe,
482 .remove = mq1100fb_platform_remove,
483 .suspend = mq1100fb_platform_suspend,
484 .resume = mq1100fb_platform_resume
487 static int __init mq1100fb_init(void)
489 return driver_register (&mq1100fb_device_driver);
492 static void __exit mq1100fb_exit(void)
494 driver_unregister (&mq1100fb_device_driver);
497 module_init(mq1100fb_init);
498 module_exit(mq1100fb_exit);
500 MODULE_AUTHOR("Keith Packard <keithp@keithp.com>");
501 MODULE_DESCRIPTION("Framebuffer driver for MediaQ 1100/32/68/78/88 chips");
502 MODULE_LICENSE("GPL");