]> Git Repo - linux.git/blob - drivers/video/fbdev/sm501fb.c
Linux 6.14-rc3
[linux.git] / drivers / video / fbdev / sm501fb.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* linux/drivers/video/sm501fb.c
3  *
4  * Copyright (c) 2006 Simtec Electronics
5  *      Vincent Sanders <[email protected]>
6  *      Ben Dooks <[email protected]>
7  *
8  * Framebuffer driver for the Silicon Motion SM501
9  */
10
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/string.h>
15 #include <linux/mm.h>
16 #include <linux/tty.h>
17 #include <linux/slab.h>
18 #include <linux/delay.h>
19 #include <linux/fb.h>
20 #include <linux/init.h>
21 #include <linux/vmalloc.h>
22 #include <linux/dma-mapping.h>
23 #include <linux/interrupt.h>
24 #include <linux/workqueue.h>
25 #include <linux/wait.h>
26 #include <linux/platform_device.h>
27 #include <linux/clk.h>
28 #include <linux/console.h>
29 #include <linux/io.h>
30 #include <linux/string_choices.h>
31
32 #include <linux/uaccess.h>
33 #include <asm/div64.h>
34
35 #ifdef CONFIG_PM
36 #include <linux/pm.h>
37 #endif
38
39 #include <linux/sm501.h>
40 #include <linux/sm501-regs.h>
41
42 #include "edid.h"
43
44 static char *fb_mode = "640x480-16@60";
45 static unsigned long default_bpp = 16;
46
47 static const struct fb_videomode sm501_default_mode = {
48         .refresh        = 60,
49         .xres           = 640,
50         .yres           = 480,
51         .pixclock       = 20833,
52         .left_margin    = 142,
53         .right_margin   = 13,
54         .upper_margin   = 21,
55         .lower_margin   = 1,
56         .hsync_len      = 69,
57         .vsync_len      = 3,
58         .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
59         .vmode          = FB_VMODE_NONINTERLACED
60 };
61
62 #define NR_PALETTE      256
63
64 enum sm501_controller {
65         HEAD_CRT        = 0,
66         HEAD_PANEL      = 1,
67 };
68
69 /* SM501 memory address.
70  *
71  * This structure is used to track memory usage within the SM501 framebuffer
72  * allocation. The sm_addr field is stored as an offset as it is often used
73  * against both the physical and mapped addresses.
74  */
75 struct sm501_mem {
76         unsigned long    size;
77         unsigned long    sm_addr;       /* offset from base of sm501 fb. */
78         void __iomem    *k_addr;
79 };
80
81 /* private data that is shared between all frambuffers* */
82 struct sm501fb_info {
83         struct device           *dev;
84         struct fb_info          *fb[2];         /* fb info for both heads */
85         struct resource         *fbmem_res;     /* framebuffer resource */
86         struct resource         *regs_res;      /* registers resource */
87         struct resource         *regs2d_res;    /* 2d registers resource */
88         struct sm501_platdata_fb *pdata;        /* our platform data */
89
90         unsigned long            pm_crt_ctrl;   /* pm: crt ctrl save */
91
92         int                      irq;
93         int                      swap_endian;   /* set to swap rgb=>bgr */
94         void __iomem            *regs;          /* remapped registers */
95         void __iomem            *regs2d;        /* 2d remapped registers */
96         void __iomem            *fbmem;         /* remapped framebuffer */
97         size_t                   fbmem_len;     /* length of remapped region */
98         u8 *edid_data;
99 };
100
101 /* per-framebuffer private data */
102 struct sm501fb_par {
103         u32                      pseudo_palette[16];
104
105         enum sm501_controller    head;
106         struct sm501_mem         cursor;
107         struct sm501_mem         screen;
108         struct fb_ops            ops;
109
110         void                    *store_fb;
111         void                    *store_cursor;
112         void __iomem            *cursor_regs;
113         struct sm501fb_info     *info;
114 };
115
116 /* Helper functions */
117
118 static inline int h_total(struct fb_var_screeninfo *var)
119 {
120         return var->xres + var->left_margin +
121                 var->right_margin + var->hsync_len;
122 }
123
124 static inline int v_total(struct fb_var_screeninfo *var)
125 {
126         return var->yres + var->upper_margin +
127                 var->lower_margin + var->vsync_len;
128 }
129
130 /* sm501fb_sync_regs()
131  *
132  * This call is mainly for PCI bus systems where we need to
133  * ensure that any writes to the bus are completed before the
134  * next phase, or after completing a function.
135 */
136
137 static inline void sm501fb_sync_regs(struct sm501fb_info *info)
138 {
139         smc501_readl(info->regs);
140 }
141
142 /* sm501_alloc_mem
143  *
144  * This is an attempt to lay out memory for the two framebuffers and
145  * everything else
146  *
147  * |fbmem_res->start                                           fbmem_res->end|
148  * |                                                                         |
149  * |fb[0].fix.smem_start    |         |fb[1].fix.smem_start    |     2K      |
150  * |-> fb[0].fix.smem_len <-| spare   |-> fb[1].fix.smem_len <-|-> cursors <-|
151  *
152  * The "spare" space is for the 2d engine data
153  * the fixed is space for the cursors (2x1Kbyte)
154  *
155  * we need to allocate memory for the 2D acceleration engine
156  * command list and the data for the engine to deal with.
157  *
158  * - all allocations must be 128bit aligned
159  * - cursors are 64x64x2 bits (1Kbyte)
160  *
161  */
162
163 #define SM501_MEMF_CURSOR               (1)
164 #define SM501_MEMF_PANEL                (2)
165 #define SM501_MEMF_CRT                  (4)
166 #define SM501_MEMF_ACCEL                (8)
167
168 static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
169                            unsigned int why, size_t size, u32 smem_len)
170 {
171         struct sm501fb_par *par;
172         struct fb_info *fbi;
173         unsigned int ptr;
174         unsigned int end;
175
176         switch (why) {
177         case SM501_MEMF_CURSOR:
178                 ptr = inf->fbmem_len - size;
179                 inf->fbmem_len = ptr;   /* adjust available memory. */
180                 break;
181
182         case SM501_MEMF_PANEL:
183                 if (size > inf->fbmem_len)
184                         return -ENOMEM;
185
186                 ptr = inf->fbmem_len - size;
187                 fbi = inf->fb[HEAD_CRT];
188
189                 /* round down, some programs such as directfb do not draw
190                  * 0,0 correctly unless the start is aligned to a page start.
191                  */
192
193                 if (ptr > 0)
194                         ptr &= ~(PAGE_SIZE - 1);
195
196                 if (fbi && ptr < smem_len)
197                         return -ENOMEM;
198
199                 break;
200
201         case SM501_MEMF_CRT:
202                 ptr = 0;
203
204                 /* check to see if we have panel memory allocated
205                  * which would put an limit on available memory. */
206
207                 fbi = inf->fb[HEAD_PANEL];
208                 if (fbi) {
209                         par = fbi->par;
210                         end = par->screen.k_addr ? par->screen.sm_addr : inf->fbmem_len;
211                 } else
212                         end = inf->fbmem_len;
213
214                 if ((ptr + size) > end)
215                         return -ENOMEM;
216
217                 break;
218
219         case SM501_MEMF_ACCEL:
220                 fbi = inf->fb[HEAD_CRT];
221                 ptr = fbi ? smem_len : 0;
222
223                 fbi = inf->fb[HEAD_PANEL];
224                 if (fbi) {
225                         par = fbi->par;
226                         end = par->screen.sm_addr;
227                 } else
228                         end = inf->fbmem_len;
229
230                 if ((ptr + size) > end)
231                         return -ENOMEM;
232
233                 break;
234
235         default:
236                 return -EINVAL;
237         }
238
239         mem->size    = size;
240         mem->sm_addr = ptr;
241         mem->k_addr  = inf->fbmem + ptr;
242
243         dev_dbg(inf->dev, "%s: result %08lx, %p - %u, %zd\n",
244                 __func__, mem->sm_addr, mem->k_addr, why, size);
245
246         return 0;
247 }
248
249 /* sm501fb_ps_to_hz
250  *
251  * Converts a period in picoseconds to Hz.
252  *
253  * Note, we try to keep this in Hz to minimise rounding with
254  * the limited PLL settings on the SM501.
255 */
256
257 static unsigned long sm501fb_ps_to_hz(unsigned long psvalue)
258 {
259         unsigned long long numerator=1000000000000ULL;
260
261         /* 10^12 / picosecond period gives frequency in Hz */
262         do_div(numerator, psvalue);
263         return (unsigned long)numerator;
264 }
265
266 /* sm501fb_hz_to_ps is identical to the opposite transform */
267
268 #define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x)
269
270 /* sm501fb_setup_gamma
271  *
272  * Programs a linear 1.0 gamma ramp in case the gamma
273  * correction is enabled without programming anything else.
274 */
275
276 static void sm501fb_setup_gamma(struct sm501fb_info *fbi,
277                                 unsigned long palette)
278 {
279         unsigned long value = 0;
280         int offset;
281
282         /* set gamma values */
283         for (offset = 0; offset < 256 * 4; offset += 4) {
284                 smc501_writel(value, fbi->regs + palette + offset);
285                 value += 0x010101;      /* Advance RGB by 1,1,1.*/
286         }
287 }
288
289 /* sm501fb_check_var
290  *
291  * check common variables for both panel and crt
292 */
293
294 static int sm501fb_check_var(struct fb_var_screeninfo *var,
295                              struct fb_info *info)
296 {
297         struct sm501fb_par  *par = info->par;
298         struct sm501fb_info *sm  = par->info;
299         unsigned long tmp;
300
301         /* check we can fit these values into the registers */
302
303         if (var->hsync_len > 255 || var->vsync_len > 63)
304                 return -EINVAL;
305
306         /* hdisplay end and hsync start */
307         if ((var->xres + var->right_margin) > 4096)
308                 return -EINVAL;
309
310         /* vdisplay end and vsync start */
311         if ((var->yres + var->lower_margin) > 2048)
312                 return -EINVAL;
313
314         /* hard limits of device */
315
316         if (h_total(var) > 4096 || v_total(var) > 2048)
317                 return -EINVAL;
318
319         /* check our line length is going to be 128 bit aligned */
320
321         tmp = (var->xres * var->bits_per_pixel) / 8;
322         if ((tmp & 15) != 0)
323                 return -EINVAL;
324
325         /* check the virtual size */
326
327         if (var->xres_virtual > 4096 || var->yres_virtual > 2048)
328                 return -EINVAL;
329
330         /* can cope with 8,16 or 32bpp */
331
332         if (var->bits_per_pixel <= 8)
333                 var->bits_per_pixel = 8;
334         else if (var->bits_per_pixel <= 16)
335                 var->bits_per_pixel = 16;
336         else if (var->bits_per_pixel == 24)
337                 var->bits_per_pixel = 32;
338
339         /* set r/g/b positions and validate bpp */
340         switch(var->bits_per_pixel) {
341         case 8:
342                 var->red.length         = var->bits_per_pixel;
343                 var->red.offset         = 0;
344                 var->green.length       = var->bits_per_pixel;
345                 var->green.offset       = 0;
346                 var->blue.length        = var->bits_per_pixel;
347                 var->blue.offset        = 0;
348                 var->transp.length      = 0;
349                 var->transp.offset      = 0;
350
351                 break;
352
353         case 16:
354                 if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
355                         var->blue.offset        = 11;
356                         var->green.offset       = 5;
357                         var->red.offset         = 0;
358                 } else {
359                         var->red.offset         = 11;
360                         var->green.offset       = 5;
361                         var->blue.offset        = 0;
362                 }
363                 var->transp.offset      = 0;
364
365                 var->red.length         = 5;
366                 var->green.length       = 6;
367                 var->blue.length        = 5;
368                 var->transp.length      = 0;
369                 break;
370
371         case 32:
372                 if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
373                         var->transp.offset      = 0;
374                         var->red.offset         = 8;
375                         var->green.offset       = 16;
376                         var->blue.offset        = 24;
377                 } else {
378                         var->transp.offset      = 24;
379                         var->red.offset         = 16;
380                         var->green.offset       = 8;
381                         var->blue.offset        = 0;
382                 }
383
384                 var->red.length         = 8;
385                 var->green.length       = 8;
386                 var->blue.length        = 8;
387                 var->transp.length      = 0;
388                 break;
389
390         default:
391                 return -EINVAL;
392         }
393
394         return 0;
395 }
396
397 /*
398  * sm501fb_check_var_crt():
399  *
400  * check the parameters for the CRT head, and either bring them
401  * back into range, or return -EINVAL.
402 */
403
404 static int sm501fb_check_var_crt(struct fb_var_screeninfo *var,
405                                  struct fb_info *info)
406 {
407         return sm501fb_check_var(var, info);
408 }
409
410 /* sm501fb_check_var_pnl():
411  *
412  * check the parameters for the CRT head, and either bring them
413  * back into range, or return -EINVAL.
414 */
415
416 static int sm501fb_check_var_pnl(struct fb_var_screeninfo *var,
417                                  struct fb_info *info)
418 {
419         return sm501fb_check_var(var, info);
420 }
421
422 /* sm501fb_set_par_common
423  *
424  * set common registers for framebuffers
425 */
426
427 static int sm501fb_set_par_common(struct fb_info *info,
428                                   struct fb_var_screeninfo *var)
429 {
430         struct sm501fb_par  *par = info->par;
431         struct sm501fb_info *fbi = par->info;
432         unsigned long pixclock;      /* pixelclock in Hz */
433         unsigned long sm501pixclock; /* pixelclock the 501 can achieve in Hz */
434         unsigned int mem_type;
435         unsigned int clock_type;
436         unsigned int head_addr;
437         unsigned int smem_len;
438
439         dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
440                 __func__, var->xres, var->yres, var->bits_per_pixel,
441                 var->xres_virtual, var->yres_virtual);
442
443         switch (par->head) {
444         case HEAD_CRT:
445                 mem_type = SM501_MEMF_CRT;
446                 clock_type = SM501_CLOCK_V2XCLK;
447                 head_addr = SM501_DC_CRT_FB_ADDR;
448                 break;
449
450         case HEAD_PANEL:
451                 mem_type = SM501_MEMF_PANEL;
452                 clock_type = SM501_CLOCK_P2XCLK;
453                 head_addr = SM501_DC_PANEL_FB_ADDR;
454                 break;
455
456         default:
457                 mem_type = 0;           /* stop compiler warnings */
458                 head_addr = 0;
459                 clock_type = 0;
460         }
461
462         switch (var->bits_per_pixel) {
463         case 8:
464                 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
465                 break;
466
467         case 16:
468                 info->fix.visual = FB_VISUAL_TRUECOLOR;
469                 break;
470
471         case 32:
472                 info->fix.visual = FB_VISUAL_TRUECOLOR;
473                 break;
474         }
475
476         /* allocate fb memory within 501 */
477         info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
478         smem_len = info->fix.line_length * var->yres_virtual;
479
480         dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
481                 info->fix.line_length);
482
483         if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) {
484                 dev_err(fbi->dev, "no memory available\n");
485                 return -ENOMEM;
486         }
487
488         mutex_lock(&info->mm_lock);
489         info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
490         info->fix.smem_len   = smem_len;
491         mutex_unlock(&info->mm_lock);
492
493         info->screen_base = fbi->fbmem + par->screen.sm_addr;
494         info->screen_size = info->fix.smem_len;
495
496         /* set start of framebuffer to the screen */
497
498         smc501_writel(par->screen.sm_addr | SM501_ADDR_FLIP,
499                         fbi->regs + head_addr);
500
501         /* program CRT clock  */
502
503         pixclock = sm501fb_ps_to_hz(var->pixclock);
504
505         sm501pixclock = sm501_set_clock(fbi->dev->parent, clock_type,
506                                         pixclock);
507
508         /* update fb layer with actual clock used */
509         var->pixclock = sm501fb_hz_to_ps(sm501pixclock);
510
511         dev_dbg(fbi->dev, "%s: pixclock(ps) = %u, pixclock(Hz)  = %lu, "
512                "sm501pixclock = %lu,  error = %ld%%\n",
513                __func__, var->pixclock, pixclock, sm501pixclock,
514                ((pixclock - sm501pixclock)*100)/pixclock);
515
516         return 0;
517 }
518
519 /* sm501fb_set_par_geometry
520  *
521  * set the geometry registers for specified framebuffer.
522 */
523
524 static void sm501fb_set_par_geometry(struct fb_info *info,
525                                      struct fb_var_screeninfo *var)
526 {
527         struct sm501fb_par  *par = info->par;
528         struct sm501fb_info *fbi = par->info;
529         void __iomem *base = fbi->regs;
530         unsigned long reg;
531
532         if (par->head == HEAD_CRT)
533                 base += SM501_DC_CRT_H_TOT;
534         else
535                 base += SM501_DC_PANEL_H_TOT;
536
537         /* set framebuffer width and display width */
538
539         reg = info->fix.line_length;
540         reg |= ((var->xres * var->bits_per_pixel)/8) << 16;
541
542         smc501_writel(reg, fbi->regs + (par->head == HEAD_CRT ?
543                     SM501_DC_CRT_FB_OFFSET :  SM501_DC_PANEL_FB_OFFSET));
544
545         /* program horizontal total */
546
547         reg  = (h_total(var) - 1) << 16;
548         reg |= (var->xres - 1);
549
550         smc501_writel(reg, base + SM501_OFF_DC_H_TOT);
551
552         /* program horizontal sync */
553
554         reg  = var->hsync_len << 16;
555         reg |= var->xres + var->right_margin - 1;
556
557         smc501_writel(reg, base + SM501_OFF_DC_H_SYNC);
558
559         /* program vertical total */
560
561         reg  = (v_total(var) - 1) << 16;
562         reg |= (var->yres - 1);
563
564         smc501_writel(reg, base + SM501_OFF_DC_V_TOT);
565
566         /* program vertical sync */
567         reg  = var->vsync_len << 16;
568         reg |= var->yres + var->lower_margin - 1;
569
570         smc501_writel(reg, base + SM501_OFF_DC_V_SYNC);
571 }
572
573 /* sm501fb_pan_crt
574  *
575  * pan the CRT display output within an virtual framebuffer
576 */
577
578 static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
579                            struct fb_info *info)
580 {
581         struct sm501fb_par  *par = info->par;
582         struct sm501fb_info *fbi = par->info;
583         unsigned int bytes_pixel = info->var.bits_per_pixel / 8;
584         unsigned long reg;
585         unsigned long xoffs;
586
587         xoffs = var->xoffset * bytes_pixel;
588
589         reg = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
590
591         reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK;
592         reg |= ((xoffs & 15) / bytes_pixel) << 4;
593         smc501_writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
594
595         reg = (par->screen.sm_addr + xoffs +
596                var->yoffset * info->fix.line_length);
597         smc501_writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
598
599         sm501fb_sync_regs(fbi);
600         return 0;
601 }
602
603 /* sm501fb_pan_pnl
604  *
605  * pan the panel display output within an virtual framebuffer
606 */
607
608 static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
609                            struct fb_info *info)
610 {
611         struct sm501fb_par  *par = info->par;
612         struct sm501fb_info *fbi = par->info;
613         unsigned long reg;
614
615         reg = var->xoffset | (info->var.xres_virtual << 16);
616         smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
617
618         reg = var->yoffset | (info->var.yres_virtual << 16);
619         smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
620
621         sm501fb_sync_regs(fbi);
622         return 0;
623 }
624
625 /* sm501fb_set_par_crt
626  *
627  * Set the CRT video mode from the fb_info structure
628 */
629
630 static int sm501fb_set_par_crt(struct fb_info *info)
631 {
632         struct sm501fb_par  *par = info->par;
633         struct sm501fb_info *fbi = par->info;
634         struct fb_var_screeninfo *var = &info->var;
635         unsigned long control;       /* control register */
636         int ret;
637
638         /* activate new configuration */
639
640         dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
641
642         /* enable CRT DAC - note 0 is on!*/
643         sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
644
645         control = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
646
647         control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK |
648                     SM501_DC_CRT_CONTROL_GAMMA |
649                     SM501_DC_CRT_CONTROL_BLANK |
650                     SM501_DC_CRT_CONTROL_SEL |
651                     SM501_DC_CRT_CONTROL_CP |
652                     SM501_DC_CRT_CONTROL_TVP);
653
654         /* set the sync polarities before we check data source  */
655
656         if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
657                 control |= SM501_DC_CRT_CONTROL_HSP;
658
659         if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
660                 control |= SM501_DC_CRT_CONTROL_VSP;
661
662         if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
663                 /* the head is displaying panel data... */
664
665                 sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0,
666                                 info->fix.smem_len);
667                 goto out_update;
668         }
669
670         ret = sm501fb_set_par_common(info, var);
671         if (ret) {
672                 dev_err(fbi->dev, "failed to set common parameters\n");
673                 return ret;
674         }
675
676         sm501fb_pan_crt(var, info);
677         sm501fb_set_par_geometry(info, var);
678
679         control |= SM501_FIFO_3;        /* fill if >3 free slots */
680
681         switch(var->bits_per_pixel) {
682         case 8:
683                 control |= SM501_DC_CRT_CONTROL_8BPP;
684                 break;
685
686         case 16:
687                 control |= SM501_DC_CRT_CONTROL_16BPP;
688                 sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);
689                 break;
690
691         case 32:
692                 control |= SM501_DC_CRT_CONTROL_32BPP;
693                 sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);
694                 break;
695
696         default:
697                 BUG();
698         }
699
700         control |= SM501_DC_CRT_CONTROL_SEL;    /* CRT displays CRT data */
701         control |= SM501_DC_CRT_CONTROL_TE;     /* enable CRT timing */
702         control |= SM501_DC_CRT_CONTROL_ENABLE; /* enable CRT plane */
703
704  out_update:
705         dev_dbg(fbi->dev, "new control is %08lx\n", control);
706
707         smc501_writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
708         sm501fb_sync_regs(fbi);
709
710         return 0;
711 }
712
713 static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
714 {
715         unsigned long control;
716         void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
717         struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl;
718
719         control = smc501_readl(ctrl_reg);
720
721         if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) {
722                 /* enable panel power */
723
724                 control |= SM501_DC_PANEL_CONTROL_VDD;  /* FPVDDEN */
725                 smc501_writel(control, ctrl_reg);
726                 sm501fb_sync_regs(fbi);
727                 mdelay(10);
728
729                 control |= SM501_DC_PANEL_CONTROL_DATA; /* DATA */
730                 smc501_writel(control, ctrl_reg);
731                 sm501fb_sync_regs(fbi);
732                 mdelay(10);
733
734                 /* VBIASEN */
735
736                 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
737                         if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)
738                                 control &= ~SM501_DC_PANEL_CONTROL_BIAS;
739                         else
740                                 control |= SM501_DC_PANEL_CONTROL_BIAS;
741
742                         smc501_writel(control, ctrl_reg);
743                         sm501fb_sync_regs(fbi);
744                         mdelay(10);
745                 }
746
747                 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
748                         if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)
749                                 control &= ~SM501_DC_PANEL_CONTROL_FPEN;
750                         else
751                                 control |= SM501_DC_PANEL_CONTROL_FPEN;
752
753                         smc501_writel(control, ctrl_reg);
754                         sm501fb_sync_regs(fbi);
755                         mdelay(10);
756                 }
757         } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
758                 /* disable panel power */
759                 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
760                         if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)
761                                 control |= SM501_DC_PANEL_CONTROL_FPEN;
762                         else
763                                 control &= ~SM501_DC_PANEL_CONTROL_FPEN;
764
765                         smc501_writel(control, ctrl_reg);
766                         sm501fb_sync_regs(fbi);
767                         mdelay(10);
768                 }
769
770                 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
771                         if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)
772                                 control |= SM501_DC_PANEL_CONTROL_BIAS;
773                         else
774                                 control &= ~SM501_DC_PANEL_CONTROL_BIAS;
775
776                         smc501_writel(control, ctrl_reg);
777                         sm501fb_sync_regs(fbi);
778                         mdelay(10);
779                 }
780
781                 control &= ~SM501_DC_PANEL_CONTROL_DATA;
782                 smc501_writel(control, ctrl_reg);
783                 sm501fb_sync_regs(fbi);
784                 mdelay(10);
785
786                 control &= ~SM501_DC_PANEL_CONTROL_VDD;
787                 smc501_writel(control, ctrl_reg);
788                 sm501fb_sync_regs(fbi);
789                 mdelay(10);
790         }
791
792         sm501fb_sync_regs(fbi);
793 }
794
795 /* sm501fb_set_par_pnl
796  *
797  * Set the panel video mode from the fb_info structure
798 */
799
800 static int sm501fb_set_par_pnl(struct fb_info *info)
801 {
802         struct sm501fb_par  *par = info->par;
803         struct sm501fb_info *fbi = par->info;
804         struct fb_var_screeninfo *var = &info->var;
805         unsigned long control;
806         unsigned long reg;
807         int ret;
808
809         dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
810
811         /* activate this new configuration */
812
813         ret = sm501fb_set_par_common(info, var);
814         if (ret)
815                 return ret;
816
817         sm501fb_pan_pnl(var, info);
818         sm501fb_set_par_geometry(info, var);
819
820         /* update control register */
821
822         control = smc501_readl(fbi->regs + SM501_DC_PANEL_CONTROL);
823         control &= (SM501_DC_PANEL_CONTROL_GAMMA |
824                     SM501_DC_PANEL_CONTROL_VDD  |
825                     SM501_DC_PANEL_CONTROL_DATA |
826                     SM501_DC_PANEL_CONTROL_BIAS |
827                     SM501_DC_PANEL_CONTROL_FPEN |
828                     SM501_DC_PANEL_CONTROL_CP |
829                     SM501_DC_PANEL_CONTROL_CK |
830                     SM501_DC_PANEL_CONTROL_HP |
831                     SM501_DC_PANEL_CONTROL_VP |
832                     SM501_DC_PANEL_CONTROL_HPD |
833                     SM501_DC_PANEL_CONTROL_VPD);
834
835         control |= SM501_FIFO_3;        /* fill if >3 free slots */
836
837         switch(var->bits_per_pixel) {
838         case 8:
839                 control |= SM501_DC_PANEL_CONTROL_8BPP;
840                 break;
841
842         case 16:
843                 control |= SM501_DC_PANEL_CONTROL_16BPP;
844                 sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);
845                 break;
846
847         case 32:
848                 control |= SM501_DC_PANEL_CONTROL_32BPP;
849                 sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);
850                 break;
851
852         default:
853                 BUG();
854         }
855
856         smc501_writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
857
858         /* panel plane top left and bottom right location */
859
860         smc501_writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
861
862         reg  = var->xres - 1;
863         reg |= (var->yres - 1) << 16;
864
865         smc501_writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
866
867         /* program panel control register */
868
869         control |= SM501_DC_PANEL_CONTROL_TE;   /* enable PANEL timing */
870         control |= SM501_DC_PANEL_CONTROL_EN;   /* enable PANEL gfx plane */
871
872         if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
873                 control |= SM501_DC_PANEL_CONTROL_HSP;
874
875         if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
876                 control |= SM501_DC_PANEL_CONTROL_VSP;
877
878         smc501_writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
879         sm501fb_sync_regs(fbi);
880
881         /* ensure the panel interface is not tristated at this point */
882
883         sm501_modify_reg(fbi->dev->parent, SM501_SYSTEM_CONTROL,
884                          0, SM501_SYSCTRL_PANEL_TRISTATE);
885
886         /* power the panel up */
887         sm501fb_panel_power(fbi, 1);
888         return 0;
889 }
890
891
892 /* chan_to_field
893  *
894  * convert a colour value into a field position
895  *
896  * from pxafb.c
897 */
898
899 static inline unsigned int chan_to_field(unsigned int chan,
900                                          struct fb_bitfield *bf)
901 {
902         chan &= 0xffff;
903         chan >>= 16 - bf->length;
904         return chan << bf->offset;
905 }
906
907 /* sm501fb_setcolreg
908  *
909  * set the colour mapping for modes that support palettised data
910 */
911
912 static int sm501fb_setcolreg(unsigned regno,
913                              unsigned red, unsigned green, unsigned blue,
914                              unsigned transp, struct fb_info *info)
915 {
916         struct sm501fb_par  *par = info->par;
917         struct sm501fb_info *fbi = par->info;
918         void __iomem *base = fbi->regs;
919         unsigned int val;
920
921         if (par->head == HEAD_CRT)
922                 base += SM501_DC_CRT_PALETTE;
923         else
924                 base += SM501_DC_PANEL_PALETTE;
925
926         switch (info->fix.visual) {
927         case FB_VISUAL_TRUECOLOR:
928                 /* true-colour, use pseuo-palette */
929
930                 if (regno < 16) {
931                         u32 *pal = par->pseudo_palette;
932
933                         val  = chan_to_field(red,   &info->var.red);
934                         val |= chan_to_field(green, &info->var.green);
935                         val |= chan_to_field(blue,  &info->var.blue);
936
937                         pal[regno] = val;
938                 }
939                 break;
940
941         case FB_VISUAL_PSEUDOCOLOR:
942                 if (regno < 256) {
943                         val = (red >> 8) << 16;
944                         val |= (green >> 8) << 8;
945                         val |= blue >> 8;
946
947                         smc501_writel(val, base + (regno * 4));
948                 }
949
950                 break;
951
952         default:
953                 return 1;   /* unknown type */
954         }
955
956         return 0;
957 }
958
959 /* sm501fb_blank_pnl
960  *
961  * Blank or un-blank the panel interface
962 */
963
964 static int sm501fb_blank_pnl(int blank_mode, struct fb_info *info)
965 {
966         struct sm501fb_par  *par = info->par;
967         struct sm501fb_info *fbi = par->info;
968
969         dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
970
971         switch (blank_mode) {
972         case FB_BLANK_POWERDOWN:
973                 sm501fb_panel_power(fbi, 0);
974                 break;
975
976         case FB_BLANK_UNBLANK:
977                 sm501fb_panel_power(fbi, 1);
978                 break;
979
980         case FB_BLANK_NORMAL:
981         case FB_BLANK_VSYNC_SUSPEND:
982         case FB_BLANK_HSYNC_SUSPEND:
983         default:
984                 return 1;
985         }
986
987         return 0;
988 }
989
990 /* sm501fb_blank_crt
991  *
992  * Blank or un-blank the crt interface
993 */
994
995 static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
996 {
997         struct sm501fb_par  *par = info->par;
998         struct sm501fb_info *fbi = par->info;
999         unsigned long ctrl;
1000
1001         dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
1002
1003         ctrl = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
1004
1005         switch (blank_mode) {
1006         case FB_BLANK_POWERDOWN:
1007                 ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
1008                 sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);
1009                 fallthrough;
1010
1011         case FB_BLANK_NORMAL:
1012                 ctrl |= SM501_DC_CRT_CONTROL_BLANK;
1013                 break;
1014
1015         case FB_BLANK_UNBLANK:
1016                 ctrl &= ~SM501_DC_CRT_CONTROL_BLANK;
1017                 ctrl |=  SM501_DC_CRT_CONTROL_ENABLE;
1018                 sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
1019                 break;
1020
1021         case FB_BLANK_VSYNC_SUSPEND:
1022         case FB_BLANK_HSYNC_SUSPEND:
1023         default:
1024                 return 1;
1025
1026         }
1027
1028         smc501_writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
1029         sm501fb_sync_regs(fbi);
1030
1031         return 0;
1032 }
1033
1034 /* sm501fb_cursor
1035  *
1036  * set or change the hardware cursor parameters
1037 */
1038
1039 static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
1040 {
1041         struct sm501fb_par  *par = info->par;
1042         struct sm501fb_info *fbi = par->info;
1043         void __iomem *base = fbi->regs;
1044         unsigned long hwc_addr;
1045         unsigned long fg, bg;
1046
1047         dev_dbg(fbi->dev, "%s(%p,%p)\n", __func__, info, cursor);
1048
1049         if (par->head == HEAD_CRT)
1050                 base += SM501_DC_CRT_HWC_BASE;
1051         else
1052                 base += SM501_DC_PANEL_HWC_BASE;
1053
1054         /* check not being asked to exceed capabilities */
1055
1056         if (cursor->image.width > 64)
1057                 return -EINVAL;
1058
1059         if (cursor->image.height > 64)
1060                 return -EINVAL;
1061
1062         if (cursor->image.depth > 1)
1063                 return -EINVAL;
1064
1065         hwc_addr = smc501_readl(base + SM501_OFF_HWC_ADDR);
1066
1067         if (cursor->enable)
1068                 smc501_writel(hwc_addr | SM501_HWC_EN,
1069                                 base + SM501_OFF_HWC_ADDR);
1070         else
1071                 smc501_writel(hwc_addr & ~SM501_HWC_EN,
1072                                 base + SM501_OFF_HWC_ADDR);
1073
1074         /* set data */
1075         if (cursor->set & FB_CUR_SETPOS) {
1076                 unsigned int x = cursor->image.dx;
1077                 unsigned int y = cursor->image.dy;
1078
1079                 if (x >= 2048 || y >= 2048 )
1080                         return -EINVAL;
1081
1082                 dev_dbg(fbi->dev, "set position %d,%d\n", x, y);
1083
1084                 //y += cursor->image.height;
1085
1086                 smc501_writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
1087         }
1088
1089         if (cursor->set & FB_CUR_SETCMAP) {
1090                 unsigned int bg_col = cursor->image.bg_color;
1091                 unsigned int fg_col = cursor->image.fg_color;
1092
1093                 dev_dbg(fbi->dev, "%s: update cmap (%08x,%08x)\n",
1094                         __func__, bg_col, fg_col);
1095
1096                 bg = ((info->cmap.red[bg_col] & 0xF8) << 8) |
1097                         ((info->cmap.green[bg_col] & 0xFC) << 3) |
1098                         ((info->cmap.blue[bg_col] & 0xF8) >> 3);
1099
1100                 fg = ((info->cmap.red[fg_col] & 0xF8) << 8) |
1101                         ((info->cmap.green[fg_col] & 0xFC) << 3) |
1102                         ((info->cmap.blue[fg_col] & 0xF8) >> 3);
1103
1104                 dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg);
1105
1106                 smc501_writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
1107                 smc501_writel(fg, base + SM501_OFF_HWC_COLOR_3);
1108         }
1109
1110         if (cursor->set & FB_CUR_SETSIZE ||
1111             cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
1112                 /* SM501 cursor is a two bpp 64x64 bitmap this routine
1113                  * clears it to transparent then combines the cursor
1114                  * shape plane with the colour plane to set the
1115                  * cursor */
1116                 int x, y;
1117                 const unsigned char *pcol = cursor->image.data;
1118                 const unsigned char *pmsk = cursor->mask;
1119                 void __iomem   *dst = par->cursor.k_addr;
1120                 unsigned char  dcol = 0;
1121                 unsigned char  dmsk = 0;
1122                 unsigned int   op;
1123
1124                 dev_dbg(fbi->dev, "%s: setting shape (%d,%d)\n",
1125                         __func__, cursor->image.width, cursor->image.height);
1126
1127                 for (op = 0; op < (64*64*2)/8; op+=4)
1128                         smc501_writel(0x0, dst + op);
1129
1130                 for (y = 0; y < cursor->image.height; y++) {
1131                         for (x = 0; x < cursor->image.width; x++) {
1132                                 if ((x % 8) == 0) {
1133                                         dcol = *pcol++;
1134                                         dmsk = *pmsk++;
1135                                 } else {
1136                                         dcol >>= 1;
1137                                         dmsk >>= 1;
1138                                 }
1139
1140                                 if (dmsk & 1) {
1141                                         op = (dcol & 1) ? 1 : 3;
1142                                         op <<= ((x % 4) * 2);
1143
1144                                         op |= readb(dst + (x / 4));
1145                                         writeb(op, dst + (x / 4));
1146                                 }
1147                         }
1148                         dst += (64*2)/8;
1149                 }
1150         }
1151
1152         sm501fb_sync_regs(fbi); /* ensure cursor data flushed */
1153         return 0;
1154 }
1155
1156 /* sm501fb_crtsrc_show
1157  *
1158  * device attribute code to show where the crt output is sourced from
1159 */
1160
1161 static ssize_t sm501fb_crtsrc_show(struct device *dev,
1162                                struct device_attribute *attr, char *buf)
1163 {
1164         struct sm501fb_info *info = dev_get_drvdata(dev);
1165         unsigned long ctrl;
1166
1167         ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
1168         ctrl &= SM501_DC_CRT_CONTROL_SEL;
1169
1170         return sysfs_emit(buf, "%s\n", ctrl ? "crt" : "panel");
1171 }
1172
1173 /* sm501fb_crtsrc_show
1174  *
1175  * device attribute code to set where the crt output is sourced from
1176 */
1177
1178 static ssize_t sm501fb_crtsrc_store(struct device *dev,
1179                                 struct device_attribute *attr,
1180                                 const char *buf, size_t len)
1181 {
1182         struct sm501fb_info *info = dev_get_drvdata(dev);
1183         enum sm501_controller head;
1184         unsigned long ctrl;
1185
1186         if (len < 1)
1187                 return -EINVAL;
1188
1189         if (strncasecmp(buf, "crt", 3) == 0)
1190                 head = HEAD_CRT;
1191         else if (strncasecmp(buf, "panel", 5) == 0)
1192                 head = HEAD_PANEL;
1193         else
1194                 return -EINVAL;
1195
1196         dev_info(dev, "setting crt source to head %d\n", head);
1197
1198         ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
1199
1200         if (head == HEAD_CRT) {
1201                 ctrl |= SM501_DC_CRT_CONTROL_SEL;
1202                 ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
1203                 ctrl |= SM501_DC_CRT_CONTROL_TE;
1204         } else {
1205                 ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
1206                 ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
1207                 ctrl &= ~SM501_DC_CRT_CONTROL_TE;
1208         }
1209
1210         smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
1211         sm501fb_sync_regs(info);
1212
1213         return len;
1214 }
1215
1216 /* Prepare the device_attr for registration with sysfs later */
1217 static DEVICE_ATTR(crt_src, 0664, sm501fb_crtsrc_show, sm501fb_crtsrc_store);
1218
1219 /* sm501fb_show_regs
1220  *
1221  * show the primary sm501 registers
1222 */
1223 static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr,
1224                              unsigned int start, unsigned int len)
1225 {
1226         void __iomem *mem = info->regs;
1227         char *buf = ptr;
1228         unsigned int reg;
1229
1230         for (reg = start; reg < (len + start); reg += 4)
1231                 ptr += sprintf(ptr, "%08x = %08x\n", reg,
1232                                 smc501_readl(mem + reg));
1233
1234         return ptr - buf;
1235 }
1236
1237 /* sm501fb_debug_show_crt
1238  *
1239  * show the crt control and cursor registers
1240 */
1241
1242 static ssize_t sm501fb_debug_show_crt(struct device *dev,
1243                                   struct device_attribute *attr, char *buf)
1244 {
1245         struct sm501fb_info *info = dev_get_drvdata(dev);
1246         char *ptr = buf;
1247
1248         ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_CONTROL, 0x40);
1249         ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_HWC_BASE, 0x10);
1250
1251         return ptr - buf;
1252 }
1253
1254 static DEVICE_ATTR(fbregs_crt, 0444, sm501fb_debug_show_crt, NULL);
1255
1256 /* sm501fb_debug_show_pnl
1257  *
1258  * show the panel control and cursor registers
1259 */
1260
1261 static ssize_t sm501fb_debug_show_pnl(struct device *dev,
1262                                   struct device_attribute *attr, char *buf)
1263 {
1264         struct sm501fb_info *info = dev_get_drvdata(dev);
1265         char *ptr = buf;
1266
1267         ptr += sm501fb_show_regs(info, ptr, 0x0, 0x40);
1268         ptr += sm501fb_show_regs(info, ptr, SM501_DC_PANEL_HWC_BASE, 0x10);
1269
1270         return ptr - buf;
1271 }
1272
1273 static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);
1274
1275 static struct attribute *sm501fb_attrs[] = {
1276         &dev_attr_crt_src.attr,
1277         &dev_attr_fbregs_pnl.attr,
1278         &dev_attr_fbregs_crt.attr,
1279         NULL,
1280 };
1281 ATTRIBUTE_GROUPS(sm501fb);
1282
1283 /* acceleration operations */
1284 static int sm501fb_sync(struct fb_info *info)
1285 {
1286         int count = 1000000;
1287         struct sm501fb_par  *par = info->par;
1288         struct sm501fb_info *fbi = par->info;
1289
1290         /* wait for the 2d engine to be ready */
1291         while ((count > 0) &&
1292                (smc501_readl(fbi->regs + SM501_SYSTEM_CONTROL) &
1293                 SM501_SYSCTRL_2D_ENGINE_STATUS) != 0)
1294                 count--;
1295
1296         if (count <= 0) {
1297                 fb_err(info, "Timeout waiting for 2d engine sync\n");
1298                 return 1;
1299         }
1300         return 0;
1301 }
1302
1303 static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1304 {
1305         struct sm501fb_par  *par = info->par;
1306         struct sm501fb_info *fbi = par->info;
1307         int width = area->width;
1308         int height = area->height;
1309         int sx = area->sx;
1310         int sy = area->sy;
1311         int dx = area->dx;
1312         int dy = area->dy;
1313         unsigned long rtl = 0;
1314
1315         /* source clip */
1316         if ((sx >= info->var.xres_virtual) ||
1317             (sy >= info->var.yres_virtual))
1318                 /* source Area not within virtual screen, skipping */
1319                 return;
1320         if ((sx + width) >= info->var.xres_virtual)
1321                 width = info->var.xres_virtual - sx - 1;
1322         if ((sy + height) >= info->var.yres_virtual)
1323                 height = info->var.yres_virtual - sy - 1;
1324
1325         /* dest clip */
1326         if ((dx >= info->var.xres_virtual) ||
1327             (dy >= info->var.yres_virtual))
1328                 /* Destination Area not within virtual screen, skipping */
1329                 return;
1330         if ((dx + width) >= info->var.xres_virtual)
1331                 width = info->var.xres_virtual - dx - 1;
1332         if ((dy + height) >= info->var.yres_virtual)
1333                 height = info->var.yres_virtual - dy - 1;
1334
1335         if ((sx < dx) || (sy < dy)) {
1336                 rtl = 1 << 27;
1337                 sx += width - 1;
1338                 dx += width - 1;
1339                 sy += height - 1;
1340                 dy += height - 1;
1341         }
1342
1343         if (sm501fb_sync(info))
1344                 return;
1345
1346         /* set the base addresses */
1347         smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
1348         smc501_writel(par->screen.sm_addr,
1349                         fbi->regs2d + SM501_2D_DESTINATION_BASE);
1350
1351         /* set the window width */
1352         smc501_writel((info->var.xres << 16) | info->var.xres,
1353                fbi->regs2d + SM501_2D_WINDOW_WIDTH);
1354
1355         /* set window stride */
1356         smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
1357                fbi->regs2d + SM501_2D_PITCH);
1358
1359         /* set data format */
1360         switch (info->var.bits_per_pixel) {
1361         case 8:
1362                 smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH);
1363                 break;
1364         case 16:
1365                 smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
1366                 break;
1367         case 32:
1368                 smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
1369                 break;
1370         }
1371
1372         /* 2d compare mask */
1373         smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
1374
1375         /* 2d mask */
1376         smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
1377
1378         /* source and destination x y */
1379         smc501_writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE);
1380         smc501_writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION);
1381
1382         /* w/h */
1383         smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
1384
1385         /* do area move */
1386         smc501_writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL);
1387 }
1388
1389 static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
1390 {
1391         struct sm501fb_par  *par = info->par;
1392         struct sm501fb_info *fbi = par->info;
1393         int width = rect->width, height = rect->height;
1394
1395         if ((rect->dx >= info->var.xres_virtual) ||
1396             (rect->dy >= info->var.yres_virtual))
1397                 /* Rectangle not within virtual screen, skipping */
1398                 return;
1399         if ((rect->dx + width) >= info->var.xres_virtual)
1400                 width = info->var.xres_virtual - rect->dx - 1;
1401         if ((rect->dy + height) >= info->var.yres_virtual)
1402                 height = info->var.yres_virtual - rect->dy - 1;
1403
1404         if (sm501fb_sync(info))
1405                 return;
1406
1407         /* set the base addresses */
1408         smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
1409         smc501_writel(par->screen.sm_addr,
1410                         fbi->regs2d + SM501_2D_DESTINATION_BASE);
1411
1412         /* set the window width */
1413         smc501_writel((info->var.xres << 16) | info->var.xres,
1414                fbi->regs2d + SM501_2D_WINDOW_WIDTH);
1415
1416         /* set window stride */
1417         smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
1418                fbi->regs2d + SM501_2D_PITCH);
1419
1420         /* set data format */
1421         switch (info->var.bits_per_pixel) {
1422         case 8:
1423                 smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH);
1424                 break;
1425         case 16:
1426                 smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
1427                 break;
1428         case 32:
1429                 smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
1430                 break;
1431         }
1432
1433         /* 2d compare mask */
1434         smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
1435
1436         /* 2d mask */
1437         smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
1438
1439         /* colour */
1440         smc501_writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND);
1441
1442         /* x y */
1443         smc501_writel((rect->dx << 16) | rect->dy,
1444                         fbi->regs2d + SM501_2D_DESTINATION);
1445
1446         /* w/h */
1447         smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
1448
1449         /* do rectangle fill */
1450         smc501_writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL);
1451 }
1452
1453
1454 static struct fb_ops sm501fb_ops_crt = {
1455         .owner          = THIS_MODULE,
1456         __FB_DEFAULT_IOMEM_OPS_RDWR,
1457         .fb_check_var   = sm501fb_check_var_crt,
1458         .fb_set_par     = sm501fb_set_par_crt,
1459         .fb_blank       = sm501fb_blank_crt,
1460         .fb_setcolreg   = sm501fb_setcolreg,
1461         .fb_pan_display = sm501fb_pan_crt,
1462         .fb_cursor      = sm501fb_cursor,
1463         .fb_fillrect    = sm501fb_fillrect,
1464         .fb_copyarea    = sm501fb_copyarea,
1465         .fb_imageblit   = cfb_imageblit,
1466         .fb_sync        = sm501fb_sync,
1467         __FB_DEFAULT_IOMEM_OPS_MMAP,
1468 };
1469
1470 static struct fb_ops sm501fb_ops_pnl = {
1471         .owner          = THIS_MODULE,
1472         __FB_DEFAULT_IOMEM_OPS_RDWR,
1473         .fb_check_var   = sm501fb_check_var_pnl,
1474         .fb_set_par     = sm501fb_set_par_pnl,
1475         .fb_pan_display = sm501fb_pan_pnl,
1476         .fb_blank       = sm501fb_blank_pnl,
1477         .fb_setcolreg   = sm501fb_setcolreg,
1478         .fb_cursor      = sm501fb_cursor,
1479         .fb_fillrect    = sm501fb_fillrect,
1480         .fb_copyarea    = sm501fb_copyarea,
1481         .fb_imageblit   = cfb_imageblit,
1482         .fb_sync        = sm501fb_sync,
1483         __FB_DEFAULT_IOMEM_OPS_MMAP,
1484 };
1485
1486 /* sm501_init_cursor
1487  *
1488  * initialise hw cursor parameters
1489 */
1490
1491 static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
1492 {
1493         struct sm501fb_par *par;
1494         struct sm501fb_info *info;
1495         int ret;
1496
1497         if (fbi == NULL)
1498                 return 0;
1499
1500         par = fbi->par;
1501         info = par->info;
1502
1503         par->cursor_regs = info->regs + reg_base;
1504
1505         ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024,
1506                               fbi->fix.smem_len);
1507         if (ret < 0)
1508                 return ret;
1509
1510         /* initialise the colour registers */
1511
1512         smc501_writel(par->cursor.sm_addr,
1513                         par->cursor_regs + SM501_OFF_HWC_ADDR);
1514
1515         smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
1516         smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
1517         smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
1518         sm501fb_sync_regs(info);
1519
1520         return 0;
1521 }
1522
1523 /* sm501fb_info_start
1524  *
1525  * fills the par structure claiming resources and remapping etc.
1526 */
1527
1528 static int sm501fb_start(struct sm501fb_info *info,
1529                          struct platform_device *pdev)
1530 {
1531         struct resource *res;
1532         struct device *dev = &pdev->dev;
1533         int k;
1534         int ret;
1535
1536         info->irq = ret = platform_get_irq(pdev, 0);
1537         if (ret < 0) {
1538                 /* we currently do not use the IRQ */
1539                 dev_warn(dev, "no irq for device\n");
1540         }
1541
1542         /* allocate, reserve and remap resources for display
1543          * controller registers */
1544         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1545         if (res == NULL) {
1546                 dev_err(dev, "no resource definition for registers\n");
1547                 ret = -ENOENT;
1548                 goto err_release;
1549         }
1550
1551         info->regs_res = request_mem_region(res->start,
1552                                             resource_size(res),
1553                                             pdev->name);
1554
1555         if (info->regs_res == NULL) {
1556                 dev_err(dev, "cannot claim registers\n");
1557                 ret = -ENXIO;
1558                 goto err_release;
1559         }
1560
1561         info->regs = ioremap(res->start, resource_size(res));
1562         if (info->regs == NULL) {
1563                 dev_err(dev, "cannot remap registers\n");
1564                 ret = -ENXIO;
1565                 goto err_regs_res;
1566         }
1567
1568         /* allocate, reserve and remap resources for 2d
1569          * controller registers */
1570         res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1571         if (res == NULL) {
1572                 dev_err(dev, "no resource definition for 2d registers\n");
1573                 ret = -ENOENT;
1574                 goto err_regs_map;
1575         }
1576
1577         info->regs2d_res = request_mem_region(res->start,
1578                                               resource_size(res),
1579                                               pdev->name);
1580
1581         if (info->regs2d_res == NULL) {
1582                 dev_err(dev, "cannot claim registers\n");
1583                 ret = -ENXIO;
1584                 goto err_regs_map;
1585         }
1586
1587         info->regs2d = ioremap(res->start, resource_size(res));
1588         if (info->regs2d == NULL) {
1589                 dev_err(dev, "cannot remap registers\n");
1590                 ret = -ENXIO;
1591                 goto err_regs2d_res;
1592         }
1593
1594         /* allocate, reserve resources for framebuffer */
1595         res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
1596         if (res == NULL) {
1597                 dev_err(dev, "no memory resource defined\n");
1598                 ret = -ENXIO;
1599                 goto err_regs2d_map;
1600         }
1601
1602         info->fbmem_res = request_mem_region(res->start,
1603                                              resource_size(res),
1604                                              pdev->name);
1605         if (info->fbmem_res == NULL) {
1606                 dev_err(dev, "cannot claim framebuffer\n");
1607                 ret = -ENXIO;
1608                 goto err_regs2d_map;
1609         }
1610
1611         info->fbmem = ioremap(res->start, resource_size(res));
1612         if (info->fbmem == NULL) {
1613                 dev_err(dev, "cannot remap framebuffer\n");
1614                 ret = -ENXIO;
1615                 goto err_mem_res;
1616         }
1617
1618         info->fbmem_len = resource_size(res);
1619
1620         /* clear framebuffer memory - avoids garbage data on unused fb */
1621         memset_io(info->fbmem, 0, info->fbmem_len);
1622
1623         /* clear palette ram - undefined at power on */
1624         for (k = 0; k < (256 * 3); k++)
1625                 smc501_writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
1626
1627         /* enable display controller */
1628         sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
1629
1630         /* enable 2d controller */
1631         sm501_unit_power(dev->parent, SM501_GATE_2D_ENGINE, 1);
1632
1633         /* setup cursors */
1634         sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);
1635         sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);
1636
1637         return 0; /* everything is setup */
1638
1639  err_mem_res:
1640         release_mem_region(info->fbmem_res->start,
1641                            resource_size(info->fbmem_res));
1642
1643  err_regs2d_map:
1644         iounmap(info->regs2d);
1645
1646  err_regs2d_res:
1647         release_mem_region(info->regs2d_res->start,
1648                            resource_size(info->regs2d_res));
1649
1650  err_regs_map:
1651         iounmap(info->regs);
1652
1653  err_regs_res:
1654         release_mem_region(info->regs_res->start,
1655                            resource_size(info->regs_res));
1656
1657  err_release:
1658         return ret;
1659 }
1660
1661 static void sm501fb_stop(struct sm501fb_info *info)
1662 {
1663         /* disable display controller */
1664         sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
1665
1666         iounmap(info->fbmem);
1667         release_mem_region(info->fbmem_res->start,
1668                            resource_size(info->fbmem_res));
1669
1670         iounmap(info->regs2d);
1671         release_mem_region(info->regs2d_res->start,
1672                            resource_size(info->regs2d_res));
1673
1674         iounmap(info->regs);
1675         release_mem_region(info->regs_res->start,
1676                            resource_size(info->regs_res));
1677 }
1678
1679 static int sm501fb_init_fb(struct fb_info *fb, enum sm501_controller head,
1680                            const char *fbname)
1681 {
1682         struct sm501_platdata_fbsub *pd;
1683         struct sm501fb_par *par = fb->par;
1684         struct sm501fb_info *info = par->info;
1685         unsigned long ctrl;
1686         unsigned int enable;
1687         int ret;
1688
1689         switch (head) {
1690         case HEAD_CRT:
1691                 pd = info->pdata->fb_crt;
1692                 ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
1693                 enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0;
1694
1695                 /* ensure we set the correct source register */
1696                 if (info->pdata->fb_route != SM501_FB_CRT_PANEL) {
1697                         ctrl |= SM501_DC_CRT_CONTROL_SEL;
1698                         smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
1699                 }
1700
1701                 break;
1702
1703         case HEAD_PANEL:
1704                 pd = info->pdata->fb_pnl;
1705                 ctrl = smc501_readl(info->regs + SM501_DC_PANEL_CONTROL);
1706                 enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0;
1707                 break;
1708
1709         default:
1710                 pd = NULL;              /* stop compiler warnings */
1711                 ctrl = 0;
1712                 enable = 0;
1713                 BUG();
1714         }
1715
1716         dev_info(info->dev, "fb %s %s at start\n",
1717                  fbname, str_enabled_disabled(enable));
1718
1719         /* check to see if our routing allows this */
1720
1721         if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) {
1722                 ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
1723                 smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
1724                 enable = 0;
1725         }
1726
1727         strscpy(fb->fix.id, fbname, sizeof(fb->fix.id));
1728
1729         memcpy(&par->ops,
1730                (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl,
1731                sizeof(struct fb_ops));
1732
1733         /* update ops dependent on what we've been passed */
1734
1735         if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0)
1736                 par->ops.fb_cursor = NULL;
1737
1738         fb->fbops = &par->ops;
1739         fb->flags = FBINFO_READS_FAST |
1740                 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
1741                 FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
1742
1743 #if defined(CONFIG_OF)
1744 #ifdef __BIG_ENDIAN
1745         if (of_property_read_bool(info->dev->parent->of_node, "little-endian"))
1746                 fb->flags |= FBINFO_FOREIGN_ENDIAN;
1747 #else
1748         if (of_property_read_bool(info->dev->parent->of_node, "big-endian"))
1749                 fb->flags |= FBINFO_FOREIGN_ENDIAN;
1750 #endif
1751 #endif
1752         /* fixed data */
1753
1754         fb->fix.type            = FB_TYPE_PACKED_PIXELS;
1755         fb->fix.type_aux        = 0;
1756         fb->fix.xpanstep        = 1;
1757         fb->fix.ypanstep        = 1;
1758         fb->fix.ywrapstep       = 0;
1759         fb->fix.accel           = FB_ACCEL_NONE;
1760
1761         /* screenmode */
1762
1763         fb->var.nonstd          = 0;
1764         fb->var.activate        = FB_ACTIVATE_NOW;
1765         fb->var.accel_flags     = 0;
1766         fb->var.vmode           = FB_VMODE_NONINTERLACED;
1767         fb->var.bits_per_pixel  = 16;
1768
1769         if (info->edid_data) {
1770                         /* Now build modedb from EDID */
1771                         fb_edid_to_monspecs(info->edid_data, &fb->monspecs);
1772                         fb_videomode_to_modelist(fb->monspecs.modedb,
1773                                                  fb->monspecs.modedb_len,
1774                                                  &fb->modelist);
1775         }
1776
1777         if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
1778                 /* TODO read the mode from the current display */
1779         } else {
1780                 if (pd->def_mode) {
1781                         dev_info(info->dev, "using supplied mode\n");
1782                         fb_videomode_to_var(&fb->var, pd->def_mode);
1783
1784                         fb->var.bits_per_pixel = pd->def_bpp ? pd->def_bpp : 8;
1785                         fb->var.xres_virtual = fb->var.xres;
1786                         fb->var.yres_virtual = fb->var.yres;
1787                 } else {
1788                         if (info->edid_data) {
1789                                 ret = fb_find_mode(&fb->var, fb, fb_mode,
1790                                         fb->monspecs.modedb,
1791                                         fb->monspecs.modedb_len,
1792                                         &sm501_default_mode, default_bpp);
1793                                 /* edid_data is no longer needed, free it */
1794                                 kfree(info->edid_data);
1795                         } else {
1796                                 ret = fb_find_mode(&fb->var, fb,
1797                                            NULL, NULL, 0, NULL, 8);
1798                         }
1799
1800                         switch (ret) {
1801                         case 1:
1802                                 dev_info(info->dev, "using mode specified in "
1803                                                 "@mode\n");
1804                                 break;
1805                         case 2:
1806                                 dev_info(info->dev, "using mode specified in "
1807                                         "@mode with ignored refresh rate\n");
1808                                 break;
1809                         case 3:
1810                                 dev_info(info->dev, "using mode default "
1811                                         "mode\n");
1812                                 break;
1813                         case 4:
1814                                 dev_info(info->dev, "using mode from list\n");
1815                                 break;
1816                         default:
1817                                 dev_info(info->dev, "ret = %d\n", ret);
1818                                 dev_info(info->dev, "failed to find mode\n");
1819                                 return -EINVAL;
1820                         }
1821                 }
1822         }
1823
1824         /* initialise and set the palette */
1825         if (fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0)) {
1826                 dev_err(info->dev, "failed to allocate cmap memory\n");
1827                 return -ENOMEM;
1828         }
1829         fb_set_cmap(&fb->cmap, fb);
1830
1831         ret = (fb->fbops->fb_check_var)(&fb->var, fb);
1832         if (ret)
1833                 dev_err(info->dev, "check_var() failed on initial setup?\n");
1834
1835         return 0;
1836 }
1837
1838 /* default platform data if none is supplied (ie, PCI device) */
1839
1840 static struct sm501_platdata_fbsub sm501fb_pdata_crt = {
1841         .flags          = (SM501FB_FLAG_USE_INIT_MODE |
1842                            SM501FB_FLAG_USE_HWCURSOR |
1843                            SM501FB_FLAG_USE_HWACCEL |
1844                            SM501FB_FLAG_DISABLE_AT_EXIT),
1845
1846 };
1847
1848 static struct sm501_platdata_fbsub sm501fb_pdata_pnl = {
1849         .flags          = (SM501FB_FLAG_USE_INIT_MODE |
1850                            SM501FB_FLAG_USE_HWCURSOR |
1851                            SM501FB_FLAG_USE_HWACCEL |
1852                            SM501FB_FLAG_DISABLE_AT_EXIT),
1853 };
1854
1855 static struct sm501_platdata_fb sm501fb_def_pdata = {
1856         .fb_route               = SM501_FB_OWN,
1857         .fb_crt                 = &sm501fb_pdata_crt,
1858         .fb_pnl                 = &sm501fb_pdata_pnl,
1859 };
1860
1861 static char driver_name_crt[] = "sm501fb-crt";
1862 static char driver_name_pnl[] = "sm501fb-panel";
1863
1864 static int sm501fb_probe_one(struct sm501fb_info *info,
1865                              enum sm501_controller head)
1866 {
1867         unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel";
1868         struct sm501_platdata_fbsub *pd;
1869         struct sm501fb_par *par;
1870         struct fb_info *fbi;
1871
1872         pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl;
1873
1874         /* Do not initialise if we've not been given any platform data */
1875         if (pd == NULL) {
1876                 dev_info(info->dev, "no data for fb %s (disabled)\n", name);
1877                 return 0;
1878         }
1879
1880         fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev);
1881         if (!fbi)
1882                 return -ENOMEM;
1883
1884         par = fbi->par;
1885         par->info = info;
1886         par->head = head;
1887         fbi->pseudo_palette = &par->pseudo_palette;
1888
1889         info->fb[head] = fbi;
1890
1891         return 0;
1892 }
1893
1894 /* Free up anything allocated by sm501fb_init_fb */
1895
1896 static void sm501_free_init_fb(struct sm501fb_info *info,
1897                                 enum sm501_controller head)
1898 {
1899         struct fb_info *fbi = info->fb[head];
1900
1901         if (!fbi)
1902                 return;
1903
1904         fb_dealloc_cmap(&fbi->cmap);
1905 }
1906
1907 static int sm501fb_start_one(struct sm501fb_info *info,
1908                              enum sm501_controller head, const char *drvname)
1909 {
1910         struct fb_info *fbi = info->fb[head];
1911         int ret;
1912
1913         if (!fbi)
1914                 return 0;
1915
1916         mutex_init(&info->fb[head]->mm_lock);
1917
1918         ret = sm501fb_init_fb(info->fb[head], head, drvname);
1919         if (ret) {
1920                 dev_err(info->dev, "cannot initialise fb %s\n", drvname);
1921                 return ret;
1922         }
1923
1924         ret = register_framebuffer(info->fb[head]);
1925         if (ret) {
1926                 dev_err(info->dev, "failed to register fb %s\n", drvname);
1927                 sm501_free_init_fb(info, head);
1928                 return ret;
1929         }
1930
1931         dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id);
1932
1933         return 0;
1934 }
1935
1936 static int sm501fb_probe(struct platform_device *pdev)
1937 {
1938         struct sm501fb_info *info;
1939         struct device *dev = &pdev->dev;
1940         int ret;
1941
1942         /* allocate our framebuffers */
1943         info = kzalloc(sizeof(*info), GFP_KERNEL);
1944         if (!info) {
1945                 dev_err(dev, "failed to allocate state\n");
1946                 return -ENOMEM;
1947         }
1948
1949         info->dev = dev = &pdev->dev;
1950         platform_set_drvdata(pdev, info);
1951
1952         if (dev->parent->platform_data) {
1953                 struct sm501_platdata *pd = dev->parent->platform_data;
1954                 info->pdata = pd->fb;
1955         }
1956
1957         if (info->pdata == NULL) {
1958                 int found = 0;
1959 #if defined(CONFIG_OF)
1960                 struct device_node *np = pdev->dev.parent->of_node;
1961                 const u8 *prop;
1962                 const char *cp;
1963                 int len;
1964
1965                 info->pdata = &sm501fb_def_pdata;
1966                 if (np) {
1967                         /* Get EDID */
1968                         cp = of_get_property(np, "mode", &len);
1969                         if (cp)
1970                                 strcpy(fb_mode, cp);
1971                         prop = of_get_property(np, "edid", &len);
1972                         if (prop && len == EDID_LENGTH) {
1973                                 info->edid_data = kmemdup(prop, EDID_LENGTH,
1974                                                           GFP_KERNEL);
1975                                 if (info->edid_data)
1976                                         found = 1;
1977                         }
1978                 }
1979 #endif
1980                 if (!found) {
1981                         dev_info(dev, "using default configuration data\n");
1982                         info->pdata = &sm501fb_def_pdata;
1983                 }
1984         }
1985
1986         /* probe for the presence of each panel */
1987
1988         ret = sm501fb_probe_one(info, HEAD_CRT);
1989         if (ret < 0) {
1990                 dev_err(dev, "failed to probe CRT\n");
1991                 goto err_alloc;
1992         }
1993
1994         ret = sm501fb_probe_one(info, HEAD_PANEL);
1995         if (ret < 0) {
1996                 dev_err(dev, "failed to probe PANEL\n");
1997                 goto err_probed_crt;
1998         }
1999
2000         if (info->fb[HEAD_PANEL] == NULL &&
2001             info->fb[HEAD_CRT] == NULL) {
2002                 dev_err(dev, "no framebuffers found\n");
2003                 ret = -ENODEV;
2004                 goto err_alloc;
2005         }
2006
2007         /* get the resources for both of the framebuffers */
2008
2009         ret = sm501fb_start(info, pdev);
2010         if (ret) {
2011                 dev_err(dev, "cannot initialise SM501\n");
2012                 goto err_probed_panel;
2013         }
2014
2015         ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt);
2016         if (ret) {
2017                 dev_err(dev, "failed to start CRT\n");
2018                 goto err_started;
2019         }
2020
2021         ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl);
2022         if (ret) {
2023                 dev_err(dev, "failed to start Panel\n");
2024                 goto err_started_crt;
2025         }
2026
2027         /* we registered, return ok */
2028         return 0;
2029
2030 err_started_crt:
2031         unregister_framebuffer(info->fb[HEAD_CRT]);
2032         sm501_free_init_fb(info, HEAD_CRT);
2033
2034 err_started:
2035         sm501fb_stop(info);
2036
2037 err_probed_panel:
2038         framebuffer_release(info->fb[HEAD_PANEL]);
2039
2040 err_probed_crt:
2041         framebuffer_release(info->fb[HEAD_CRT]);
2042
2043 err_alloc:
2044         kfree(info);
2045
2046         return ret;
2047 }
2048
2049
2050 /*
2051  *  Cleanup
2052  */
2053 static void sm501fb_remove(struct platform_device *pdev)
2054 {
2055         struct sm501fb_info *info = platform_get_drvdata(pdev);
2056         struct fb_info     *fbinfo_crt = info->fb[0];
2057         struct fb_info     *fbinfo_pnl = info->fb[1];
2058
2059         sm501_free_init_fb(info, HEAD_CRT);
2060         sm501_free_init_fb(info, HEAD_PANEL);
2061
2062         if (fbinfo_crt)
2063                 unregister_framebuffer(fbinfo_crt);
2064         if (fbinfo_pnl)
2065                 unregister_framebuffer(fbinfo_pnl);
2066
2067         sm501fb_stop(info);
2068         kfree(info);
2069
2070         framebuffer_release(fbinfo_pnl);
2071         framebuffer_release(fbinfo_crt);
2072 }
2073
2074 #ifdef CONFIG_PM
2075
2076 static int sm501fb_suspend_fb(struct sm501fb_info *info,
2077                               enum sm501_controller head)
2078 {
2079         struct fb_info *fbi = info->fb[head];
2080         struct sm501fb_par *par;
2081
2082         if (!fbi)
2083                 return 0;
2084
2085         par = fbi->par;
2086         if (par->screen.size == 0)
2087                 return 0;
2088
2089         /* blank the relevant interface to ensure unit power minimised */
2090         (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
2091
2092         /* tell console/fb driver we are suspending */
2093
2094         console_lock();
2095         fb_set_suspend(fbi, 1);
2096         console_unlock();
2097
2098         /* backup copies in case chip is powered down over suspend */
2099
2100         par->store_fb = vmalloc(par->screen.size);
2101         if (par->store_fb == NULL) {
2102                 dev_err(info->dev, "no memory to store screen\n");
2103                 return -ENOMEM;
2104         }
2105
2106         par->store_cursor = vmalloc(par->cursor.size);
2107         if (par->store_cursor == NULL) {
2108                 dev_err(info->dev, "no memory to store cursor\n");
2109                 goto err_nocursor;
2110         }
2111
2112         dev_dbg(info->dev, "suspending screen to %p\n", par->store_fb);
2113         dev_dbg(info->dev, "suspending cursor to %p\n", par->store_cursor);
2114
2115         memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
2116         memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
2117
2118         return 0;
2119
2120  err_nocursor:
2121         vfree(par->store_fb);
2122         par->store_fb = NULL;
2123
2124         return -ENOMEM;
2125 }
2126
2127 static void sm501fb_resume_fb(struct sm501fb_info *info,
2128                               enum sm501_controller head)
2129 {
2130         struct fb_info *fbi = info->fb[head];
2131         struct sm501fb_par *par;
2132
2133         if (!fbi)
2134                 return;
2135
2136         par = fbi->par;
2137         if (par->screen.size == 0)
2138                 return;
2139
2140         /* re-activate the configuration */
2141
2142         (par->ops.fb_set_par)(fbi);
2143
2144         /* restore the data */
2145
2146         dev_dbg(info->dev, "restoring screen from %p\n", par->store_fb);
2147         dev_dbg(info->dev, "restoring cursor from %p\n", par->store_cursor);
2148
2149         if (par->store_fb)
2150                 memcpy_toio(par->screen.k_addr, par->store_fb,
2151                             par->screen.size);
2152
2153         if (par->store_cursor)
2154                 memcpy_toio(par->cursor.k_addr, par->store_cursor,
2155                             par->cursor.size);
2156
2157         console_lock();
2158         fb_set_suspend(fbi, 0);
2159         console_unlock();
2160
2161         vfree(par->store_fb);
2162         vfree(par->store_cursor);
2163 }
2164
2165
2166 /* suspend and resume support */
2167
2168 static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
2169 {
2170         struct sm501fb_info *info = platform_get_drvdata(pdev);
2171
2172         /* store crt control to resume with */
2173         info->pm_crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
2174
2175         sm501fb_suspend_fb(info, HEAD_CRT);
2176         sm501fb_suspend_fb(info, HEAD_PANEL);
2177
2178         /* turn off the clocks, in case the device is not powered down */
2179         sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
2180
2181         return 0;
2182 }
2183
2184 #define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP |        \
2185                              SM501_DC_CRT_CONTROL_SEL)
2186
2187
2188 static int sm501fb_resume(struct platform_device *pdev)
2189 {
2190         struct sm501fb_info *info = platform_get_drvdata(pdev);
2191         unsigned long crt_ctrl;
2192
2193         sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1);
2194
2195         /* restore the items we want to be saved for crt control */
2196
2197         crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
2198         crt_ctrl &= ~SM501_CRT_CTRL_SAVE;
2199         crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE;
2200         smc501_writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL);
2201
2202         sm501fb_resume_fb(info, HEAD_CRT);
2203         sm501fb_resume_fb(info, HEAD_PANEL);
2204
2205         return 0;
2206 }
2207
2208 #else
2209 #define sm501fb_suspend NULL
2210 #define sm501fb_resume  NULL
2211 #endif
2212
2213 static struct platform_driver sm501fb_driver = {
2214         .probe          = sm501fb_probe,
2215         .remove         = sm501fb_remove,
2216         .suspend        = sm501fb_suspend,
2217         .resume         = sm501fb_resume,
2218         .driver         = {
2219                 .name   = "sm501-fb",
2220                 .dev_groups     = sm501fb_groups,
2221         },
2222 };
2223
2224 module_platform_driver(sm501fb_driver);
2225
2226 module_param_named(mode, fb_mode, charp, 0);
2227 MODULE_PARM_DESC(mode,
2228         "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
2229 module_param_named(bpp, default_bpp, ulong, 0);
2230 MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
2231 MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
2232 MODULE_DESCRIPTION("SM501 Framebuffer driver");
2233 MODULE_LICENSE("GPL v2");
This page took 0.159194 seconds and 4 git commands to generate.