fbdev: s1d13xxxfb: add accelerated bitblt functions
[sfrench/cifs-2.6.git] / drivers / video / s1d13xxxfb.c
1 /* drivers/video/s1d13xxxfb.c
2  *
3  * (c) 2004 Simtec Electronics
4  * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org>
5  * (c) 2009 Kristoffer Ericson <kristoffer.ericson@gmail.com>
6  *
7  * Driver for Epson S1D13xxx series framebuffer chips
8  *
9  * Adapted from
10  *  linux/drivers/video/skeletonfb.c
11  *  linux/drivers/video/epson1355fb.c
12  *  linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson)
13  *
14  * TODO: - handle dual screen display (CRT and LCD at the same time).
15  *       - check_var(), mode change, etc.
16  *       - probably not SMP safe :)
17  *       - support all bitblt operations on all cards
18  *
19  * This file is subject to the terms and conditions of the GNU General Public
20  * License. See the file COPYING in the main directory of this archive for
21  * more details.
22  */
23
24 #include <linux/module.h>
25 #include <linux/platform_device.h>
26 #include <linux/delay.h>
27 #include <linux/types.h>
28 #include <linux/errno.h>
29 #include <linux/mm.h>
30 #include <linux/mman.h>
31 #include <linux/fb.h>
32 #include <linux/spinlock_types.h>
33 #include <linux/spinlock.h>
34
35 #include <asm/io.h>
36
37 #include <video/s1d13xxxfb.h>
38
39 #define PFX     "s1d13xxxfb: "
40 #define BLIT    "s1d13xxxfb_bitblt: "
41
42 /*
43  * set this to enable debugging on general functions
44  */
45 #if 0
46 #define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0)
47 #else
48 #define dbg(fmt, args...) do { } while (0)
49 #endif
50
51 /*
52  * set this to enable debugging on 2D acceleration
53  */
54 #if 0
55 #define dbg_blit(fmt, args...) do { printk(KERN_INFO BLIT fmt, ## args); } while (0)
56 #else
57 #define dbg_blit(fmt, args...) do { } while (0)
58 #endif
59
60 /*
61  * we make sure only one bitblt operation is running
62  */
63 static DEFINE_SPINLOCK(s1d13xxxfb_bitblt_lock);
64
65 /*
66  * list of card production ids
67  */
68 static const int s1d13xxxfb_prod_ids[] = {
69         S1D13505_PROD_ID,
70         S1D13506_PROD_ID,
71         S1D13806_PROD_ID,
72 };
73
74 /*
75  * List of card strings
76  */
77 static const char *s1d13xxxfb_prod_names[] = {
78         "S1D13505",
79         "S1D13506",
80         "S1D13806",
81 };
82
83 /*
84  * here we define the default struct fb_fix_screeninfo
85  */
86 static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = {
87         .id             = S1D_FBID,
88         .type           = FB_TYPE_PACKED_PIXELS,
89         .visual         = FB_VISUAL_PSEUDOCOLOR,
90         .xpanstep       = 0,
91         .ypanstep       = 1,
92         .ywrapstep      = 0,
93         .accel          = FB_ACCEL_NONE,
94 };
95
96 static inline u8
97 s1d13xxxfb_readreg(struct s1d13xxxfb_par *par, u16 regno)
98 {
99 #if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
100         regno=((regno & 1) ? (regno & ~1L) : (regno + 1));
101 #endif
102         return readb(par->regs + regno);
103 }
104
105 static inline void
106 s1d13xxxfb_writereg(struct s1d13xxxfb_par *par, u16 regno, u8 value)
107 {
108 #if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
109         regno=((regno & 1) ? (regno & ~1L) : (regno + 1));
110 #endif
111         writeb(value, par->regs + regno);
112 }
113
114 static inline void
115 s1d13xxxfb_runinit(struct s1d13xxxfb_par *par,
116                         const struct s1d13xxxfb_regval *initregs,
117                         const unsigned int size)
118 {
119         int i;
120
121         for (i = 0; i < size; i++) {
122                 if ((initregs[i].addr == S1DREG_DELAYOFF) ||
123                                 (initregs[i].addr == S1DREG_DELAYON))
124                         mdelay((int)initregs[i].value);
125                 else {
126                         s1d13xxxfb_writereg(par, initregs[i].addr, initregs[i].value);
127                 }
128         }
129
130         /* make sure the hardware can cope with us */
131         mdelay(1);
132 }
133
134 static inline void
135 lcd_enable(struct s1d13xxxfb_par *par, int enable)
136 {
137         u8 mode = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
138
139         if (enable)
140                 mode |= 0x01;
141         else
142                 mode &= ~0x01;
143
144         s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
145 }
146
147 static inline void
148 crt_enable(struct s1d13xxxfb_par *par, int enable)
149 {
150         u8 mode = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
151
152         if (enable)
153                 mode |= 0x02;
154         else
155                 mode &= ~0x02;
156
157         s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
158 }
159
160
161 /*************************************************************
162  framebuffer control functions
163  *************************************************************/
164 static inline void
165 s1d13xxxfb_setup_pseudocolour(struct fb_info *info)
166 {
167         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
168
169         info->var.red.length = 4;
170         info->var.green.length = 4;
171         info->var.blue.length = 4;
172 }
173
174 static inline void
175 s1d13xxxfb_setup_truecolour(struct fb_info *info)
176 {
177         info->fix.visual = FB_VISUAL_TRUECOLOR;
178         info->var.bits_per_pixel = 16;
179
180         info->var.red.length = 5;
181         info->var.red.offset = 11;
182
183         info->var.green.length = 6;
184         info->var.green.offset = 5;
185
186         info->var.blue.length = 5;
187         info->var.blue.offset = 0;
188 }
189
190 /**
191  *      s1d13xxxfb_set_par - Alters the hardware state.
192  *      @info: frame buffer structure
193  *
194  *      Using the fb_var_screeninfo in fb_info we set the depth of the
195  *      framebuffer. This function alters the par AND the
196  *      fb_fix_screeninfo stored in fb_info. It doesn't not alter var in
197  *      fb_info since we are using that data. This means we depend on the
198  *      data in var inside fb_info to be supported by the hardware.
199  *      xxxfb_check_var is always called before xxxfb_set_par to ensure this.
200  *
201  *      XXX TODO: write proper s1d13xxxfb_check_var(), without which that
202  *      function is quite useless.
203  */
204 static int
205 s1d13xxxfb_set_par(struct fb_info *info)
206 {
207         struct s1d13xxxfb_par *s1dfb = info->par;
208         unsigned int val;
209
210         dbg("s1d13xxxfb_set_par: bpp=%d\n", info->var.bits_per_pixel);
211
212         if ((s1dfb->display & 0x01))    /* LCD */
213                 val = s1d13xxxfb_readreg(s1dfb, S1DREG_LCD_DISP_MODE);   /* read colour control */
214         else    /* CRT */
215                 val = s1d13xxxfb_readreg(s1dfb, S1DREG_CRT_DISP_MODE);   /* read colour control */
216
217         val &= ~0x07;
218
219         switch (info->var.bits_per_pixel) {
220                 case 4:
221                         dbg("pseudo colour 4\n");
222                         s1d13xxxfb_setup_pseudocolour(info);
223                         val |= 2;
224                         break;
225                 case 8:
226                         dbg("pseudo colour 8\n");
227                         s1d13xxxfb_setup_pseudocolour(info);
228                         val |= 3;
229                         break;
230                 case 16:
231                         dbg("true colour\n");
232                         s1d13xxxfb_setup_truecolour(info);
233                         val |= 5;
234                         break;
235
236                 default:
237                         dbg("bpp not supported!\n");
238                         return -EINVAL;
239         }
240
241         dbg("writing %02x to display mode register\n", val);
242
243         if ((s1dfb->display & 0x01))    /* LCD */
244                 s1d13xxxfb_writereg(s1dfb, S1DREG_LCD_DISP_MODE, val);
245         else    /* CRT */
246                 s1d13xxxfb_writereg(s1dfb, S1DREG_CRT_DISP_MODE, val);
247
248         info->fix.line_length  = info->var.xres * info->var.bits_per_pixel;
249         info->fix.line_length /= 8;
250
251         dbg("setting line_length to %d\n", info->fix.line_length);
252
253         dbg("done setup\n");
254
255         return 0;
256 }
257
258 /**
259  *      s1d13xxxfb_setcolreg - sets a color register.
260  *      @regno: Which register in the CLUT we are programming
261  *      @red: The red value which can be up to 16 bits wide
262  *      @green: The green value which can be up to 16 bits wide
263  *      @blue:  The blue value which can be up to 16 bits wide.
264  *      @transp: If supported the alpha value which can be up to 16 bits wide.
265  *      @info: frame buffer info structure
266  *
267  *      Returns negative errno on error, or zero on success.
268  */
269 static int
270 s1d13xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
271                         u_int transp, struct fb_info *info)
272 {
273         struct s1d13xxxfb_par *s1dfb = info->par;
274         unsigned int pseudo_val;
275
276         if (regno >= S1D_PALETTE_SIZE)
277                 return -EINVAL;
278
279         dbg("s1d13xxxfb_setcolreg: %d: rgb=%d,%d,%d, tr=%d\n",
280                     regno, red, green, blue, transp);
281
282         if (info->var.grayscale)
283                 red = green = blue = (19595*red + 38470*green + 7471*blue) >> 16;
284
285         switch (info->fix.visual) {
286                 case FB_VISUAL_TRUECOLOR:
287                         if (regno >= 16)
288                                 return -EINVAL;
289
290                         /* deal with creating pseudo-palette entries */
291
292                         pseudo_val  = (red   >> 11) << info->var.red.offset;
293                         pseudo_val |= (green >> 10) << info->var.green.offset;
294                         pseudo_val |= (blue  >> 11) << info->var.blue.offset;
295
296                         dbg("s1d13xxxfb_setcolreg: pseudo %d, val %08x\n",
297                                     regno, pseudo_val);
298
299 #if defined(CONFIG_PLAT_MAPPI)
300                         ((u32 *)info->pseudo_palette)[regno] = cpu_to_le16(pseudo_val);
301 #else
302                         ((u32 *)info->pseudo_palette)[regno] = pseudo_val;
303 #endif
304
305                         break;
306                 case FB_VISUAL_PSEUDOCOLOR:
307                         s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_ADDR, regno);
308                         s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, red);
309                         s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, green);
310                         s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, blue);
311
312                         break;
313                 default:
314                         return -ENOSYS;
315         }
316
317         dbg("s1d13xxxfb_setcolreg: done\n");
318
319         return 0;
320 }
321
322 /**
323  *      s1d13xxxfb_blank - blanks the display.
324  *      @blank_mode: the blank mode we want.
325  *      @info: frame buffer structure that represents a single frame buffer
326  *
327  *      Blank the screen if blank_mode != 0, else unblank. Return 0 if
328  *      blanking succeeded, != 0 if un-/blanking failed due to e.g. a
329  *      video mode which doesn't support it. Implements VESA suspend
330  *      and powerdown modes on hardware that supports disabling hsync/vsync:
331  *      blank_mode == 2: suspend vsync
332  *      blank_mode == 3: suspend hsync
333  *      blank_mode == 4: powerdown
334  *
335  *      Returns negative errno on error, or zero on success.
336  */
337 static int
338 s1d13xxxfb_blank(int blank_mode, struct fb_info *info)
339 {
340         struct s1d13xxxfb_par *par = info->par;
341
342         dbg("s1d13xxxfb_blank: blank=%d, info=%p\n", blank_mode, info);
343
344         switch (blank_mode) {
345                 case FB_BLANK_UNBLANK:
346                 case FB_BLANK_NORMAL:
347                         if ((par->display & 0x01) != 0)
348                                 lcd_enable(par, 1);
349                         if ((par->display & 0x02) != 0)
350                                 crt_enable(par, 1);
351                         break;
352                 case FB_BLANK_VSYNC_SUSPEND:
353                 case FB_BLANK_HSYNC_SUSPEND:
354                         break;
355                 case FB_BLANK_POWERDOWN:
356                         lcd_enable(par, 0);
357                         crt_enable(par, 0);
358                         break;
359                 default:
360                         return -EINVAL;
361         }
362
363         /* let fbcon do a soft blank for us */
364         return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
365 }
366
367 /**
368  *      s1d13xxxfb_pan_display - Pans the display.
369  *      @var: frame buffer variable screen structure
370  *      @info: frame buffer structure that represents a single frame buffer
371  *
372  *      Pan (or wrap, depending on the `vmode' field) the display using the
373  *      `yoffset' field of the `var' structure (`xoffset'  not yet supported).
374  *      If the values don't fit, return -EINVAL.
375  *
376  *      Returns negative errno on error, or zero on success.
377  */
378 static int
379 s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
380 {
381         struct s1d13xxxfb_par *par = info->par;
382         u32 start;
383
384         if (var->xoffset != 0)  /* not yet ... */
385                 return -EINVAL;
386
387         if (var->yoffset + info->var.yres > info->var.yres_virtual)
388                 return -EINVAL;
389
390         start = (info->fix.line_length >> 1) * var->yoffset;
391
392         if ((par->display & 0x01)) {
393                 /* LCD */
394                 s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START0, (start & 0xff));
395                 s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START1, ((start >> 8) & 0xff));
396                 s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START2, ((start >> 16) & 0x0f));
397         } else {
398                 /* CRT */
399                 s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START0, (start & 0xff));
400                 s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START1, ((start >> 8) & 0xff));
401                 s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START2, ((start >> 16) & 0x0f));
402         }
403
404         return 0;
405 }
406
407 /************************************************************
408  functions to handle bitblt acceleration
409  ************************************************************/
410
411 /**
412  *      bltbit_wait_bitset - waits for change in register value
413  *      @info : framebuffer structure
414  *      @bit  : value expected in register
415  *      @timeout : ...
416  *
417  *      waits until value changes INTO bit
418  */
419 static u8
420 bltbit_wait_bitset(struct fb_info *info, u8 bit, int timeout)
421 {
422         while (!(s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit)) {
423                 udelay(10);
424                 if (!--timeout) {
425                         dbg_blit("wait_bitset timeout\n");
426                         break;
427                 }
428         }
429
430         return timeout;
431 }
432
433 /**
434  *      bltbit_wait_bitclear - waits for change in register value
435  *      @info : frambuffer structure
436  *      @bit  : value currently in register
437  *      @timeout : ...
438  *
439  *      waits until value changes FROM bit
440  *
441  */
442 static u8
443 bltbit_wait_bitclear(struct fb_info *info, u8 bit, int timeout)
444 {
445         while (s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit) {
446                 udelay(10);
447                 if (!--timeout) {
448                         dbg_blit("wait_bitclear timeout\n");
449                         break;
450                 }
451         }
452
453         return timeout;
454 }
455
456 /**
457  *      bltbit_fifo_status - checks the current status of the fifo
458  *      @info : framebuffer structure
459  *
460  *      returns number of free words in buffer
461  */
462 static u8
463 bltbit_fifo_status(struct fb_info *info)
464 {
465         u8 status;
466
467         status = s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0);
468
469         /* its empty so room for 16 words */
470         if (status & BBLT_FIFO_EMPTY)
471                 return 16;
472
473         /* its full so we dont want to add */
474         if (status & BBLT_FIFO_FULL)
475                 return 0;
476
477         /* its atleast half full but we can add one atleast */
478         if (status & BBLT_FIFO_NOT_FULL)
479                 return 1;
480
481         return 0;
482 }
483
484 /*
485  *      s1d13xxxfb_bitblt_copyarea - accelerated copyarea function
486  *      @info : framebuffer structure
487  *      @area : fb_copyarea structure
488  *
489  *      supports (atleast) S1D13506
490  *
491  */
492 static void
493 s1d13xxxfb_bitblt_copyarea(struct fb_info *info, const struct fb_copyarea *area)
494 {
495         u32 dst, src;
496         u32 stride;
497         u16 reverse = 0;
498         u16 sx = area->sx, sy = area->sy;
499         u16 dx = area->dx, dy = area->dy;
500         u16 width = area->width, height = area->height;
501         u16 bpp;
502
503         spin_lock(&s1d13xxxfb_bitblt_lock);
504
505         /* bytes per xres line */
506         bpp = (info->var.bits_per_pixel >> 3);
507         stride = bpp * info->var.xres;
508
509         /* reverse, calculate the last pixel in rectangle */
510         if ((dy > sy) || ((dy == sy) && (dx >= sx))) {
511                 dst = (((dy + height - 1) * stride) + (bpp * (dx + width - 1)));
512                 src = (((sy + height - 1) * stride) + (bpp * (sx + width - 1)));
513                 reverse = 1;
514         /* not reverse, calculate the first pixel in rectangle */
515         } else { /* (y * xres) + (bpp * x) */
516                 dst = (dy * stride) + (bpp * dx);
517                 src = (sy * stride) + (bpp * sx);
518         }
519
520         /* set source adress */
521         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START0, (src & 0xff));
522         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START1, (src >> 8) & 0x00ff);
523         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START2, (src >> 16) & 0x00ff);
524
525         /* set destination adress */
526         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dst & 0xff));
527         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, (dst >> 8) & 0x00ff);
528         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, (dst >> 16) & 0x00ff);
529
530         /* program height and width */
531         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH0, (width & 0xff) - 1);
532         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH1, (width >> 8));
533
534         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT0, (height & 0xff) - 1);
535         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT1, (height >> 8));
536
537         /* negative direction ROP */
538         if (reverse == 1) {
539                 dbg_blit("(copyarea) negative rop\n");
540                 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, 0x03);
541         } else /* positive direction ROP */ {
542                 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, 0x02);
543                 dbg_blit("(copyarea) positive rop\n");
544         }
545
546         /* set for rectangel mode and not linear */
547         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0);
548
549         /* setup the bpp 1 = 16bpp, 0 = 8bpp*/
550         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (bpp >> 1));
551
552         /* set words per xres */
553         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (stride >> 1) & 0xff);
554         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (stride >> 9));
555
556         dbg_blit("(copyarea) dx=%d, dy=%d\n", dx, dy);
557         dbg_blit("(copyarea) sx=%d, sy=%d\n", sx, sy);
558         dbg_blit("(copyarea) width=%d, height=%d\n", width - 1, height - 1);
559         dbg_blit("(copyarea) stride=%d\n", stride);
560         dbg_blit("(copyarea) bpp=%d=0x0%d, mem_offset1=%d, mem_offset2=%d\n", bpp, (bpp >> 1),
561                 (stride >> 1) & 0xff, stride >> 9);
562
563         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CC_EXP, 0x0c);
564
565         /* initialize the engine */
566         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80);
567
568         /* wait to complete */
569         bltbit_wait_bitclear(info, 0x80, 8000);
570
571         spin_unlock(&s1d13xxxfb_bitblt_lock);
572 }
573
574 /**
575  *
576  *      s1d13xxxfb_bitblt_solidfill - accelerated solidfill function
577  *      @info : framebuffer structure
578  *      @rect : fb_fillrect structure
579  *
580  *      supports (atleast 13506)
581  *
582  **/
583 static void
584 s1d13xxxfb_bitblt_solidfill(struct fb_info *info, const struct fb_fillrect *rect)
585 {
586         u32 screen_stride, dest;
587         u32 fg;
588         u16 bpp = (info->var.bits_per_pixel >> 3);
589
590         /* grab spinlock */
591         spin_lock(&s1d13xxxfb_bitblt_lock);
592
593         /* bytes per x width */
594         screen_stride = (bpp * info->var.xres);
595
596         /* bytes to starting point */
597         dest = ((rect->dy * screen_stride) + (bpp * rect->dx));
598
599         dbg_blit("(solidfill) dx=%d, dy=%d, stride=%d, dest=%d\n"
600                  "(solidfill) : rect_width=%d, rect_height=%d\n",
601                                 rect->dx, rect->dy, screen_stride, dest,
602                                 rect->width - 1, rect->height - 1);
603
604         dbg_blit("(solidfill) : xres=%d, yres=%d, bpp=%d\n",
605                                 info->var.xres, info->var.yres,
606                                 info->var.bits_per_pixel);
607         dbg_blit("(solidfill) : rop=%d\n", rect->rop);
608
609         /* We split the destination into the three registers */
610         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dest & 0x00ff));
611         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, ((dest >> 8) & 0x00ff));
612         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, ((dest >> 16) & 0x00ff));
613
614         /* give information regarding rectangel width */
615         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH0, ((rect->width) & 0x00ff) - 1);
616         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH1, (rect->width >> 8));
617
618         /* give information regarding rectangel height */
619         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT0, ((rect->height) & 0x00ff) - 1);
620         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT1, (rect->height >> 8));
621
622         if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
623                 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
624                 fg = ((u32 *)info->pseudo_palette)[rect->color];
625                 dbg_blit("(solidfill) truecolor/directcolor\n");
626                 dbg_blit("(solidfill) pseudo_palette[%d] = %d\n", rect->color, fg);
627         } else {
628                 fg = rect->color;
629                 dbg_blit("(solidfill) color = %d\n", rect->color);
630         }
631
632         /* set foreground color */
633         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC0, (fg & 0xff));
634         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC1, (fg >> 8) & 0xff);
635
636         /* set rectangual region of memory (rectangle and not linear) */
637         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0);
638
639         /* set operation mode SOLID_FILL */
640         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, BBLT_SOLID_FILL);
641
642         /* set bits per pixel (1 = 16bpp, 0 = 8bpp) */
643         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (info->var.bits_per_pixel >> 4));
644
645         /* set the memory offset for the bblt in word sizes */
646         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (screen_stride >> 1) & 0x00ff);
647         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (screen_stride >> 9));
648
649         /* and away we go.... */
650         s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80);
651
652         /* wait until its done */
653         bltbit_wait_bitclear(info, 0x80, 8000);
654
655         /* let others play */
656         spin_unlock(&s1d13xxxfb_bitblt_lock);
657 }
658
659 /* framebuffer information structures */
660 static struct fb_ops s1d13xxxfb_fbops = {
661         .owner          = THIS_MODULE,
662         .fb_set_par     = s1d13xxxfb_set_par,
663         .fb_setcolreg   = s1d13xxxfb_setcolreg,
664         .fb_blank       = s1d13xxxfb_blank,
665
666         .fb_pan_display = s1d13xxxfb_pan_display,
667
668         /* gets replaced at chip detection time */
669         .fb_fillrect    = cfb_fillrect,
670         .fb_copyarea    = cfb_copyarea,
671         .fb_imageblit   = cfb_imageblit,
672 };
673
674 static int s1d13xxxfb_width_tab[2][4] __devinitdata = {
675         {4, 8, 16, -1},
676         {9, 12, 18, -1},
677 };
678
679 /**
680  *      s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to
681  *      hardware setup.
682  *      @info: frame buffer structure
683  *
684  *      We setup the framebuffer structures according to the current
685  *      hardware setup. On some machines, the BIOS will have filled
686  *      the chip registers with such info, on others, these values will
687  *      have been written in some init procedure. In any case, the
688  *      software values needs to match the hardware ones. This is what
689  *      this function ensures.
690  *
691  *      Note: some of the hardcoded values here might need some love to
692  *      work on various chips, and might need to no longer be hardcoded.
693  */
694 static void __devinit
695 s1d13xxxfb_fetch_hw_state(struct fb_info *info)
696 {
697         struct fb_var_screeninfo *var = &info->var;
698         struct fb_fix_screeninfo *fix = &info->fix;
699         struct s1d13xxxfb_par *par = info->par;
700         u8 panel, display;
701         u16 offset;
702         u32 xres, yres;
703         u32 xres_virtual, yres_virtual;
704         int bpp, lcd_bpp;
705         int is_color, is_dual, is_tft;
706         int lcd_enabled, crt_enabled;
707
708         fix->type = FB_TYPE_PACKED_PIXELS;
709
710         /* general info */
711         par->display = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
712         crt_enabled = (par->display & 0x02) != 0;
713         lcd_enabled = (par->display & 0x01) != 0;
714
715         if (lcd_enabled && crt_enabled)
716                 printk(KERN_WARNING PFX "Warning: LCD and CRT detected, using LCD\n");
717
718         if (lcd_enabled)
719                 display = s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_MODE);
720         else    /* CRT */
721                 display = s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_MODE);
722
723         bpp = display & 0x07;
724
725         switch (bpp) {
726                 case 2: /* 4 bpp */
727                 case 3: /* 8 bpp */
728                         var->bits_per_pixel = 8;
729                         var->red.offset = var->green.offset = var->blue.offset = 0;
730                         var->red.length = var->green.length = var->blue.length = 8;
731                         break;
732                 case 5: /* 16 bpp */
733                         s1d13xxxfb_setup_truecolour(info);
734                         break;
735                 default:
736                         dbg("bpp: %i\n", bpp);
737         }
738         fb_alloc_cmap(&info->cmap, 256, 0);
739
740         /* LCD info */
741         panel = s1d13xxxfb_readreg(par, S1DREG_PANEL_TYPE);
742         is_color = (panel & 0x04) != 0;
743         is_dual = (panel & 0x02) != 0;
744         is_tft = (panel & 0x01) != 0;
745         lcd_bpp = s1d13xxxfb_width_tab[is_tft][(panel >> 4) & 3];
746
747         if (lcd_enabled) {
748                 xres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_HWIDTH) + 1) * 8;
749                 yres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT0) +
750                         ((s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT1) & 0x03) << 8) + 1);
751
752                 offset = (s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF0) +
753                         ((s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF1) & 0x7) << 8));
754         } else { /* crt */
755                 xres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_HWIDTH) + 1) * 8;
756                 yres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT0) +
757                         ((s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT1) & 0x03) << 8) + 1);
758
759                 offset = (s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF0) +
760                         ((s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF1) & 0x7) << 8));
761         }
762         xres_virtual = offset * 16 / var->bits_per_pixel;
763         yres_virtual = fix->smem_len / (offset * 2);
764
765         var->xres               = xres;
766         var->yres               = yres;
767         var->xres_virtual       = xres_virtual;
768         var->yres_virtual       = yres_virtual;
769         var->xoffset            = var->yoffset = 0;
770
771         fix->line_length        = offset * 2;
772
773         var->grayscale          = !is_color;
774
775         var->activate           = FB_ACTIVATE_NOW;
776
777         dbg(PFX "bpp=%d, lcd_bpp=%d, "
778                 "crt_enabled=%d, lcd_enabled=%d\n",
779                 var->bits_per_pixel, lcd_bpp, crt_enabled, lcd_enabled);
780         dbg(PFX "xres=%d, yres=%d, vxres=%d, vyres=%d "
781                 "is_color=%d, is_dual=%d, is_tft=%d\n",
782                 xres, yres, xres_virtual, yres_virtual, is_color, is_dual, is_tft);
783 }
784
785
786 static int
787 s1d13xxxfb_remove(struct platform_device *pdev)
788 {
789         struct fb_info *info = platform_get_drvdata(pdev);
790         struct s1d13xxxfb_par *par = NULL;
791
792         if (info) {
793                 par = info->par;
794                 if (par && par->regs) {
795                         /* disable output & enable powersave */
796                         s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, 0x00);
797                         s1d13xxxfb_writereg(par, S1DREG_PS_CNF, 0x11);
798                         iounmap(par->regs);
799                 }
800
801                 fb_dealloc_cmap(&info->cmap);
802
803                 if (info->screen_base)
804                         iounmap(info->screen_base);
805
806                 framebuffer_release(info);
807         }
808
809         release_mem_region(pdev->resource[0].start,
810                         pdev->resource[0].end - pdev->resource[0].start +1);
811         release_mem_region(pdev->resource[1].start,
812                         pdev->resource[1].end - pdev->resource[1].start +1);
813         return 0;
814 }
815
816 static int __devinit
817 s1d13xxxfb_probe(struct platform_device *pdev)
818 {
819         struct s1d13xxxfb_par *default_par;
820         struct fb_info *info;
821         struct s1d13xxxfb_pdata *pdata = NULL;
822         int ret = 0;
823         int i;
824         u8 revision, prod_id;
825
826         dbg("probe called: device is %p\n", pdev);
827
828         printk(KERN_INFO "Epson S1D13XXX FB Driver\n");
829
830         /* enable platform-dependent hardware glue, if any */
831         if (pdev->dev.platform_data)
832                 pdata = pdev->dev.platform_data;
833
834         if (pdata && pdata->platform_init_video)
835                 pdata->platform_init_video();
836
837         if (pdev->num_resources != 2) {
838                 dev_err(&pdev->dev, "invalid num_resources: %i\n",
839                        pdev->num_resources);
840                 ret = -ENODEV;
841                 goto bail;
842         }
843
844         /* resource[0] is VRAM, resource[1] is registers */
845         if (pdev->resource[0].flags != IORESOURCE_MEM
846                         || pdev->resource[1].flags != IORESOURCE_MEM) {
847                 dev_err(&pdev->dev, "invalid resource type\n");
848                 ret = -ENODEV;
849                 goto bail;
850         }
851
852         if (!request_mem_region(pdev->resource[0].start,
853                 pdev->resource[0].end - pdev->resource[0].start +1, "s1d13xxxfb mem")) {
854                 dev_dbg(&pdev->dev, "request_mem_region failed\n");
855                 ret = -EBUSY;
856                 goto bail;
857         }
858
859         if (!request_mem_region(pdev->resource[1].start,
860                 pdev->resource[1].end - pdev->resource[1].start +1, "s1d13xxxfb regs")) {
861                 dev_dbg(&pdev->dev, "request_mem_region failed\n");
862                 ret = -EBUSY;
863                 goto bail;
864         }
865
866         info = framebuffer_alloc(sizeof(struct s1d13xxxfb_par) + sizeof(u32) * 256, &pdev->dev);
867         if (!info) {
868                 ret = -ENOMEM;
869                 goto bail;
870         }
871
872         platform_set_drvdata(pdev, info);
873         default_par = info->par;
874         default_par->regs = ioremap_nocache(pdev->resource[1].start,
875                         pdev->resource[1].end - pdev->resource[1].start +1);
876         if (!default_par->regs) {
877                 printk(KERN_ERR PFX "unable to map registers\n");
878                 ret = -ENOMEM;
879                 goto bail;
880         }
881         info->pseudo_palette = default_par->pseudo_palette;
882
883         info->screen_base = ioremap_nocache(pdev->resource[0].start,
884                         pdev->resource[0].end - pdev->resource[0].start +1);
885
886         if (!info->screen_base) {
887                 printk(KERN_ERR PFX "unable to map framebuffer\n");
888                 ret = -ENOMEM;
889                 goto bail;
890         }
891
892         /* production id is top 6 bits */
893         prod_id = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2;
894         /* revision id is lower 2 bits */
895         revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) & 0x3;
896         ret = -ENODEV;
897
898         for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_prod_ids); i++) {
899                 if (prod_id == s1d13xxxfb_prod_ids[i]) {
900                         /* looks like we got it in our list */
901                         default_par->prod_id = prod_id;
902                         default_par->revision = revision;
903                         ret = 0;
904                         break;
905                 }
906         }
907
908         if (!ret) {
909                 printk(KERN_INFO PFX "chip production id %i = %s\n",
910                         prod_id, s1d13xxxfb_prod_names[i]);
911                 printk(KERN_INFO PFX "chip revision %i\n", revision);
912         } else {
913                 printk(KERN_INFO PFX
914                         "unknown chip production id %i, revision %i\n",
915                         prod_id, revision);
916                 printk(KERN_INFO PFX "please contant maintainer\n");
917                 goto bail;
918         }
919
920         info->fix = s1d13xxxfb_fix;
921         info->fix.mmio_start = pdev->resource[1].start;
922         info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start + 1;
923         info->fix.smem_start = pdev->resource[0].start;
924         info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start + 1;
925
926         printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n",
927                default_par->regs, info->fix.smem_len / 1024, info->screen_base);
928
929         info->par = default_par;
930         info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
931         info->fbops = &s1d13xxxfb_fbops;
932
933         switch(prod_id) {
934         case S1D13506_PROD_ID:  /* activate acceleration */
935                 s1d13xxxfb_fbops.fb_fillrect = s1d13xxxfb_bitblt_solidfill;
936                 s1d13xxxfb_fbops.fb_copyarea = s1d13xxxfb_bitblt_copyarea;
937                 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
938                         FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA;
939                 break;
940         default:
941                 break;
942         }
943
944         /* perform "manual" chip initialization, if needed */
945         if (pdata && pdata->initregs)
946                 s1d13xxxfb_runinit(info->par, pdata->initregs, pdata->initregssize);
947
948         s1d13xxxfb_fetch_hw_state(info);
949
950         if (register_framebuffer(info) < 0) {
951                 ret = -EINVAL;
952                 goto bail;
953         }
954
955         printk(KERN_INFO "fb%d: %s frame buffer device\n",
956                info->node, info->fix.id);
957
958         return 0;
959
960 bail:
961         s1d13xxxfb_remove(pdev);
962         return ret;
963
964 }
965
966 #ifdef CONFIG_PM
967 static int s1d13xxxfb_suspend(struct platform_device *dev, pm_message_t state)
968 {
969         struct fb_info *info = platform_get_drvdata(dev);
970         struct s1d13xxxfb_par *s1dfb = info->par;
971         struct s1d13xxxfb_pdata *pdata = NULL;
972
973         /* disable display */
974         lcd_enable(s1dfb, 0);
975         crt_enable(s1dfb, 0);
976
977         if (dev->dev.platform_data)
978                 pdata = dev->dev.platform_data;
979
980 #if 0
981         if (!s1dfb->disp_save)
982                 s1dfb->disp_save = kmalloc(info->fix.smem_len, GFP_KERNEL);
983
984         if (!s1dfb->disp_save) {
985                 printk(KERN_ERR PFX "no memory to save screen");
986                 return -ENOMEM;
987         }
988
989         memcpy_fromio(s1dfb->disp_save, info->screen_base, info->fix.smem_len);
990 #else
991         s1dfb->disp_save = NULL;
992 #endif
993
994         if (!s1dfb->regs_save)
995                 s1dfb->regs_save = kmalloc(info->fix.mmio_len, GFP_KERNEL);
996
997         if (!s1dfb->regs_save) {
998                 printk(KERN_ERR PFX "no memory to save registers");
999                 return -ENOMEM;
1000         }
1001
1002         /* backup all registers */
1003         memcpy_fromio(s1dfb->regs_save, s1dfb->regs, info->fix.mmio_len);
1004
1005         /* now activate power save mode */
1006         s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x11);
1007
1008         if (pdata && pdata->platform_suspend_video)
1009                 return pdata->platform_suspend_video();
1010         else
1011                 return 0;
1012 }
1013
1014 static int s1d13xxxfb_resume(struct platform_device *dev)
1015 {
1016         struct fb_info *info = platform_get_drvdata(dev);
1017         struct s1d13xxxfb_par *s1dfb = info->par;
1018         struct s1d13xxxfb_pdata *pdata = NULL;
1019
1020         /* awaken the chip */
1021         s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x10);
1022
1023         /* do not let go until SDRAM "wakes up" */
1024         while ((s1d13xxxfb_readreg(s1dfb, S1DREG_PS_STATUS) & 0x01))
1025                 udelay(10);
1026
1027         if (dev->dev.platform_data)
1028                 pdata = dev->dev.platform_data;
1029
1030         if (s1dfb->regs_save) {
1031                 /* will write RO regs, *should* get away with it :) */
1032                 memcpy_toio(s1dfb->regs, s1dfb->regs_save, info->fix.mmio_len);
1033                 kfree(s1dfb->regs_save);
1034         }
1035
1036         if (s1dfb->disp_save) {
1037                 memcpy_toio(info->screen_base, s1dfb->disp_save,
1038                                 info->fix.smem_len);
1039                 kfree(s1dfb->disp_save);        /* XXX kmalloc()'d when? */
1040         }
1041
1042         if ((s1dfb->display & 0x01) != 0)
1043                 lcd_enable(s1dfb, 1);
1044         if ((s1dfb->display & 0x02) != 0)
1045                 crt_enable(s1dfb, 1);
1046
1047         if (pdata && pdata->platform_resume_video)
1048                 return pdata->platform_resume_video();
1049         else
1050                 return 0;
1051 }
1052 #endif /* CONFIG_PM */
1053
1054 static struct platform_driver s1d13xxxfb_driver = {
1055         .probe          = s1d13xxxfb_probe,
1056         .remove         = s1d13xxxfb_remove,
1057 #ifdef CONFIG_PM
1058         .suspend        = s1d13xxxfb_suspend,
1059         .resume         = s1d13xxxfb_resume,
1060 #endif
1061         .driver         = {
1062                 .name   = S1D_DEVICENAME,
1063         },
1064 };
1065
1066
1067 static int __init
1068 s1d13xxxfb_init(void)
1069 {
1070
1071 #ifndef MODULE
1072         if (fb_get_options("s1d13xxxfb", NULL))
1073                 return -ENODEV;
1074 #endif
1075
1076         return platform_driver_register(&s1d13xxxfb_driver);
1077 }
1078
1079
1080 static void __exit
1081 s1d13xxxfb_exit(void)
1082 {
1083         platform_driver_unregister(&s1d13xxxfb_driver);
1084 }
1085
1086 module_init(s1d13xxxfb_init);
1087 module_exit(s1d13xxxfb_exit);
1088
1089
1090 MODULE_LICENSE("GPL");
1091 MODULE_DESCRIPTION("Framebuffer driver for S1D13xxx devices");
1092 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Thibaut VARENE <varenet@parisc-linux.org>");