1 /* linux/drivers/video/sm501fb.c
3 * Copyright (c) 2006 Simtec Electronics
4 * Vincent Sanders <vince@simtec.co.uk>
5 * Ben Dooks <ben@simtec.co.uk>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * Framebuffer driver for the Silicon Motion SM501
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
19 #include <linux/tty.h>
20 #include <linux/slab.h>
21 #include <linux/delay.h>
23 #include <linux/init.h>
24 #include <linux/vmalloc.h>
25 #include <linux/dma-mapping.h>
26 #include <linux/interrupt.h>
27 #include <linux/workqueue.h>
28 #include <linux/wait.h>
29 #include <linux/platform_device.h>
30 #include <linux/clk.h>
31 #include <linux/console.h>
34 #include <asm/uaccess.h>
35 #include <asm/div64.h>
41 #include <linux/sm501.h>
42 #include <linux/sm501-regs.h>
44 #define NR_PALETTE 256
46 enum sm501_controller
{
51 /* SM501 memory address.
53 * This structure is used to track memory usage within the SM501 framebuffer
54 * allocation. The sm_addr field is stored as an offset as it is often used
55 * against both the physical and mapped addresses.
59 unsigned long sm_addr
; /* offset from base of sm501 fb. */
63 /* private data that is shared between all frambuffers* */
66 struct fb_info
*fb
[2]; /* fb info for both heads */
67 struct resource
*fbmem_res
; /* framebuffer resource */
68 struct resource
*regs_res
; /* registers resource */
69 struct sm501_platdata_fb
*pdata
; /* our platform data */
71 unsigned long pm_crt_ctrl
; /* pm: crt ctrl save */
74 int swap_endian
; /* set to swap rgb=>bgr */
75 void __iomem
*regs
; /* remapped registers */
76 void __iomem
*fbmem
; /* remapped framebuffer */
77 size_t fbmem_len
; /* length of remapped region */
80 /* per-framebuffer private data */
82 u32 pseudo_palette
[16];
84 enum sm501_controller head
;
85 struct sm501_mem cursor
;
86 struct sm501_mem screen
;
91 void __iomem
*cursor_regs
;
92 struct sm501fb_info
*info
;
95 /* Helper functions */
97 static inline int h_total(struct fb_var_screeninfo
*var
)
99 return var
->xres
+ var
->left_margin
+
100 var
->right_margin
+ var
->hsync_len
;
103 static inline int v_total(struct fb_var_screeninfo
*var
)
105 return var
->yres
+ var
->upper_margin
+
106 var
->lower_margin
+ var
->vsync_len
;
109 /* sm501fb_sync_regs()
111 * This call is mainly for PCI bus systems where we need to
112 * ensure that any writes to the bus are completed before the
113 * next phase, or after completing a function.
116 static inline void sm501fb_sync_regs(struct sm501fb_info
*info
)
123 * This is an attempt to lay out memory for the two framebuffers and
126 * |fbmem_res->start fbmem_res->end|
128 * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K |
129 * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-|
131 * The "spare" space is for the 2d engine data
132 * the fixed is space for the cursors (2x1Kbyte)
134 * we need to allocate memory for the 2D acceleration engine
135 * command list and the data for the engine to deal with.
137 * - all allocations must be 128bit aligned
138 * - cursors are 64x64x2 bits (1Kbyte)
142 #define SM501_MEMF_CURSOR (1)
143 #define SM501_MEMF_PANEL (2)
144 #define SM501_MEMF_CRT (4)
145 #define SM501_MEMF_ACCEL (8)
147 static int sm501_alloc_mem(struct sm501fb_info
*inf
, struct sm501_mem
*mem
,
148 unsigned int why
, size_t size
, u32 smem_len
)
150 struct sm501fb_par
*par
;
156 case SM501_MEMF_CURSOR
:
157 ptr
= inf
->fbmem_len
- size
;
158 inf
->fbmem_len
= ptr
; /* adjust available memory. */
161 case SM501_MEMF_PANEL
:
162 if (size
> inf
->fbmem_len
)
165 ptr
= inf
->fbmem_len
- size
;
166 fbi
= inf
->fb
[HEAD_CRT
];
168 /* round down, some programs such as directfb do not draw
169 * 0,0 correctly unless the start is aligned to a page start.
173 ptr
&= ~(PAGE_SIZE
- 1);
175 if (fbi
&& ptr
< smem_len
)
183 /* check to see if we have panel memory allocated
184 * which would put an limit on available memory. */
186 fbi
= inf
->fb
[HEAD_PANEL
];
189 end
= par
->screen
.k_addr
? par
->screen
.sm_addr
: inf
->fbmem_len
;
191 end
= inf
->fbmem_len
;
193 if ((ptr
+ size
) > end
)
198 case SM501_MEMF_ACCEL
:
199 fbi
= inf
->fb
[HEAD_CRT
];
200 ptr
= fbi
? smem_len
: 0;
202 fbi
= inf
->fb
[HEAD_PANEL
];
205 end
= par
->screen
.sm_addr
;
207 end
= inf
->fbmem_len
;
209 if ((ptr
+ size
) > end
)
220 mem
->k_addr
= inf
->fbmem
+ ptr
;
222 dev_dbg(inf
->dev
, "%s: result %08lx, %p - %u, %zd\n",
223 __func__
, mem
->sm_addr
, mem
->k_addr
, why
, size
);
230 * Converts a period in picoseconds to Hz.
232 * Note, we try to keep this in Hz to minimise rounding with
233 * the limited PLL settings on the SM501.
236 static unsigned long sm501fb_ps_to_hz(unsigned long psvalue
)
238 unsigned long long numerator
=1000000000000ULL;
240 /* 10^12 / picosecond period gives frequency in Hz */
241 do_div(numerator
, psvalue
);
242 return (unsigned long)numerator
;
245 /* sm501fb_hz_to_ps is identical to the oposite transform */
247 #define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x)
249 /* sm501fb_setup_gamma
251 * Programs a linear 1.0 gamma ramp in case the gamma
252 * correction is enabled without programming anything else.
255 static void sm501fb_setup_gamma(struct sm501fb_info
*fbi
,
256 unsigned long palette
)
258 unsigned long value
= 0;
261 /* set gamma values */
262 for (offset
= 0; offset
< 256 * 4; offset
+= 4) {
263 writel(value
, fbi
->regs
+ palette
+ offset
);
264 value
+= 0x010101; /* Advance RGB by 1,1,1.*/
270 * check common variables for both panel and crt
273 static int sm501fb_check_var(struct fb_var_screeninfo
*var
,
274 struct fb_info
*info
)
276 struct sm501fb_par
*par
= info
->par
;
277 struct sm501fb_info
*sm
= par
->info
;
280 /* check we can fit these values into the registers */
282 if (var
->hsync_len
> 255 || var
->vsync_len
> 63)
285 /* hdisplay end and hsync start */
286 if ((var
->xres
+ var
->right_margin
) > 4096)
289 /* vdisplay end and vsync start */
290 if ((var
->yres
+ var
->lower_margin
) > 2048)
293 /* hard limits of device */
295 if (h_total(var
) > 4096 || v_total(var
) > 2048)
298 /* check our line length is going to be 128 bit aligned */
300 tmp
= (var
->xres
* var
->bits_per_pixel
) / 8;
304 /* check the virtual size */
306 if (var
->xres_virtual
> 4096 || var
->yres_virtual
> 2048)
309 /* can cope with 8,16 or 32bpp */
311 if (var
->bits_per_pixel
<= 8)
312 var
->bits_per_pixel
= 8;
313 else if (var
->bits_per_pixel
<= 16)
314 var
->bits_per_pixel
= 16;
315 else if (var
->bits_per_pixel
== 24)
316 var
->bits_per_pixel
= 32;
318 /* set r/g/b positions and validate bpp */
319 switch(var
->bits_per_pixel
) {
321 var
->red
.length
= var
->bits_per_pixel
;
323 var
->green
.length
= var
->bits_per_pixel
;
324 var
->green
.offset
= 0;
325 var
->blue
.length
= var
->bits_per_pixel
;
326 var
->blue
.offset
= 0;
327 var
->transp
.length
= 0;
328 var
->transp
.offset
= 0;
333 if (sm
->pdata
->flags
& SM501_FBPD_SWAP_FB_ENDIAN
) {
334 var
->blue
.offset
= 11;
335 var
->green
.offset
= 5;
338 var
->red
.offset
= 11;
339 var
->green
.offset
= 5;
340 var
->blue
.offset
= 0;
342 var
->transp
.offset
= 0;
345 var
->green
.length
= 6;
346 var
->blue
.length
= 5;
347 var
->transp
.length
= 0;
351 if (sm
->pdata
->flags
& SM501_FBPD_SWAP_FB_ENDIAN
) {
352 var
->transp
.offset
= 0;
354 var
->green
.offset
= 16;
355 var
->blue
.offset
= 24;
357 var
->transp
.offset
= 24;
358 var
->red
.offset
= 16;
359 var
->green
.offset
= 8;
360 var
->blue
.offset
= 0;
364 var
->green
.length
= 8;
365 var
->blue
.length
= 8;
366 var
->transp
.length
= 0;
377 * sm501fb_check_var_crt():
379 * check the parameters for the CRT head, and either bring them
380 * back into range, or return -EINVAL.
383 static int sm501fb_check_var_crt(struct fb_var_screeninfo
*var
,
384 struct fb_info
*info
)
386 return sm501fb_check_var(var
, info
);
389 /* sm501fb_check_var_pnl():
391 * check the parameters for the CRT head, and either bring them
392 * back into range, or return -EINVAL.
395 static int sm501fb_check_var_pnl(struct fb_var_screeninfo
*var
,
396 struct fb_info
*info
)
398 return sm501fb_check_var(var
, info
);
401 /* sm501fb_set_par_common
403 * set common registers for framebuffers
406 static int sm501fb_set_par_common(struct fb_info
*info
,
407 struct fb_var_screeninfo
*var
)
409 struct sm501fb_par
*par
= info
->par
;
410 struct sm501fb_info
*fbi
= par
->info
;
411 unsigned long pixclock
; /* pixelclock in Hz */
412 unsigned long sm501pixclock
; /* pixelclock the 501 can achive in Hz */
413 unsigned int mem_type
;
414 unsigned int clock_type
;
415 unsigned int head_addr
;
416 unsigned int smem_len
;
418 dev_dbg(fbi
->dev
, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
419 __func__
, var
->xres
, var
->yres
, var
->bits_per_pixel
,
420 var
->xres_virtual
, var
->yres_virtual
);
424 mem_type
= SM501_MEMF_CRT
;
425 clock_type
= SM501_CLOCK_V2XCLK
;
426 head_addr
= SM501_DC_CRT_FB_ADDR
;
430 mem_type
= SM501_MEMF_PANEL
;
431 clock_type
= SM501_CLOCK_P2XCLK
;
432 head_addr
= SM501_DC_PANEL_FB_ADDR
;
436 mem_type
= 0; /* stop compiler warnings */
441 switch (var
->bits_per_pixel
) {
443 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
447 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
451 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
455 /* allocate fb memory within 501 */
456 info
->fix
.line_length
= (var
->xres_virtual
* var
->bits_per_pixel
)/8;
457 smem_len
= info
->fix
.line_length
* var
->yres_virtual
;
459 dev_dbg(fbi
->dev
, "%s: line length = %u\n", __func__
,
460 info
->fix
.line_length
);
462 if (sm501_alloc_mem(fbi
, &par
->screen
, mem_type
, smem_len
, smem_len
)) {
463 dev_err(fbi
->dev
, "no memory available\n");
467 mutex_lock(&info
->mm_lock
);
468 info
->fix
.smem_start
= fbi
->fbmem_res
->start
+ par
->screen
.sm_addr
;
469 info
->fix
.smem_len
= smem_len
;
470 mutex_unlock(&info
->mm_lock
);
472 info
->screen_base
= fbi
->fbmem
+ par
->screen
.sm_addr
;
473 info
->screen_size
= info
->fix
.smem_len
;
475 /* set start of framebuffer to the screen */
477 writel(par
->screen
.sm_addr
| SM501_ADDR_FLIP
, fbi
->regs
+ head_addr
);
479 /* program CRT clock */
481 pixclock
= sm501fb_ps_to_hz(var
->pixclock
);
483 sm501pixclock
= sm501_set_clock(fbi
->dev
->parent
, clock_type
,
486 /* update fb layer with actual clock used */
487 var
->pixclock
= sm501fb_hz_to_ps(sm501pixclock
);
489 dev_dbg(fbi
->dev
, "%s: pixclock(ps) = %u, pixclock(Hz) = %lu, "
490 "sm501pixclock = %lu, error = %ld%%\n",
491 __func__
, var
->pixclock
, pixclock
, sm501pixclock
,
492 ((pixclock
- sm501pixclock
)*100)/pixclock
);
497 /* sm501fb_set_par_geometry
499 * set the geometry registers for specified framebuffer.
502 static void sm501fb_set_par_geometry(struct fb_info
*info
,
503 struct fb_var_screeninfo
*var
)
505 struct sm501fb_par
*par
= info
->par
;
506 struct sm501fb_info
*fbi
= par
->info
;
507 void __iomem
*base
= fbi
->regs
;
510 if (par
->head
== HEAD_CRT
)
511 base
+= SM501_DC_CRT_H_TOT
;
513 base
+= SM501_DC_PANEL_H_TOT
;
515 /* set framebuffer width and display width */
517 reg
= info
->fix
.line_length
;
518 reg
|= ((var
->xres
* var
->bits_per_pixel
)/8) << 16;
520 writel(reg
, fbi
->regs
+ (par
->head
== HEAD_CRT
?
521 SM501_DC_CRT_FB_OFFSET
: SM501_DC_PANEL_FB_OFFSET
));
523 /* program horizontal total */
525 reg
= (h_total(var
) - 1) << 16;
526 reg
|= (var
->xres
- 1);
528 writel(reg
, base
+ SM501_OFF_DC_H_TOT
);
530 /* program horizontal sync */
532 reg
= var
->hsync_len
<< 16;
533 reg
|= var
->xres
+ var
->right_margin
- 1;
535 writel(reg
, base
+ SM501_OFF_DC_H_SYNC
);
537 /* program vertical total */
539 reg
= (v_total(var
) - 1) << 16;
540 reg
|= (var
->yres
- 1);
542 writel(reg
, base
+ SM501_OFF_DC_V_TOT
);
544 /* program vertical sync */
545 reg
= var
->vsync_len
<< 16;
546 reg
|= var
->yres
+ var
->lower_margin
- 1;
548 writel(reg
, base
+ SM501_OFF_DC_V_SYNC
);
553 * pan the CRT display output within an virtual framebuffer
556 static int sm501fb_pan_crt(struct fb_var_screeninfo
*var
,
557 struct fb_info
*info
)
559 struct sm501fb_par
*par
= info
->par
;
560 struct sm501fb_info
*fbi
= par
->info
;
561 unsigned int bytes_pixel
= var
->bits_per_pixel
/ 8;
565 xoffs
= var
->xoffset
* bytes_pixel
;
567 reg
= readl(fbi
->regs
+ SM501_DC_CRT_CONTROL
);
569 reg
&= ~SM501_DC_CRT_CONTROL_PIXEL_MASK
;
570 reg
|= ((xoffs
& 15) / bytes_pixel
) << 4;
571 writel(reg
, fbi
->regs
+ SM501_DC_CRT_CONTROL
);
573 reg
= (par
->screen
.sm_addr
+ xoffs
+
574 var
->yoffset
* info
->fix
.line_length
);
575 writel(reg
| SM501_ADDR_FLIP
, fbi
->regs
+ SM501_DC_CRT_FB_ADDR
);
577 sm501fb_sync_regs(fbi
);
583 * pan the panel display output within an virtual framebuffer
586 static int sm501fb_pan_pnl(struct fb_var_screeninfo
*var
,
587 struct fb_info
*info
)
589 struct sm501fb_par
*par
= info
->par
;
590 struct sm501fb_info
*fbi
= par
->info
;
593 reg
= var
->xoffset
| (var
->xres_virtual
<< 16);
594 writel(reg
, fbi
->regs
+ SM501_DC_PANEL_FB_WIDTH
);
596 reg
= var
->yoffset
| (var
->yres_virtual
<< 16);
597 writel(reg
, fbi
->regs
+ SM501_DC_PANEL_FB_HEIGHT
);
599 sm501fb_sync_regs(fbi
);
603 /* sm501fb_set_par_crt
605 * Set the CRT video mode from the fb_info structure
608 static int sm501fb_set_par_crt(struct fb_info
*info
)
610 struct sm501fb_par
*par
= info
->par
;
611 struct sm501fb_info
*fbi
= par
->info
;
612 struct fb_var_screeninfo
*var
= &info
->var
;
613 unsigned long control
; /* control register */
616 /* activate new configuration */
618 dev_dbg(fbi
->dev
, "%s(%p)\n", __func__
, info
);
620 /* enable CRT DAC - note 0 is on!*/
621 sm501_misc_control(fbi
->dev
->parent
, 0, SM501_MISC_DAC_POWER
);
623 control
= readl(fbi
->regs
+ SM501_DC_CRT_CONTROL
);
625 control
&= (SM501_DC_CRT_CONTROL_PIXEL_MASK
|
626 SM501_DC_CRT_CONTROL_GAMMA
|
627 SM501_DC_CRT_CONTROL_BLANK
|
628 SM501_DC_CRT_CONTROL_SEL
|
629 SM501_DC_CRT_CONTROL_CP
|
630 SM501_DC_CRT_CONTROL_TVP
);
632 /* set the sync polarities before we check data source */
634 if ((var
->sync
& FB_SYNC_HOR_HIGH_ACT
) == 0)
635 control
|= SM501_DC_CRT_CONTROL_HSP
;
637 if ((var
->sync
& FB_SYNC_VERT_HIGH_ACT
) == 0)
638 control
|= SM501_DC_CRT_CONTROL_VSP
;
640 if ((control
& SM501_DC_CRT_CONTROL_SEL
) == 0) {
641 /* the head is displaying panel data... */
643 sm501_alloc_mem(fbi
, &par
->screen
, SM501_MEMF_CRT
, 0,
648 ret
= sm501fb_set_par_common(info
, var
);
650 dev_err(fbi
->dev
, "failed to set common parameters\n");
654 sm501fb_pan_crt(var
, info
);
655 sm501fb_set_par_geometry(info
, var
);
657 control
|= SM501_FIFO_3
; /* fill if >3 free slots */
659 switch(var
->bits_per_pixel
) {
661 control
|= SM501_DC_CRT_CONTROL_8BPP
;
665 control
|= SM501_DC_CRT_CONTROL_16BPP
;
666 sm501fb_setup_gamma(fbi
, SM501_DC_CRT_PALETTE
);
670 control
|= SM501_DC_CRT_CONTROL_32BPP
;
671 sm501fb_setup_gamma(fbi
, SM501_DC_CRT_PALETTE
);
678 control
|= SM501_DC_CRT_CONTROL_SEL
; /* CRT displays CRT data */
679 control
|= SM501_DC_CRT_CONTROL_TE
; /* enable CRT timing */
680 control
|= SM501_DC_CRT_CONTROL_ENABLE
; /* enable CRT plane */
683 dev_dbg(fbi
->dev
, "new control is %08lx\n", control
);
685 writel(control
, fbi
->regs
+ SM501_DC_CRT_CONTROL
);
686 sm501fb_sync_regs(fbi
);
691 static void sm501fb_panel_power(struct sm501fb_info
*fbi
, int to
)
693 unsigned long control
;
694 void __iomem
*ctrl_reg
= fbi
->regs
+ SM501_DC_PANEL_CONTROL
;
695 struct sm501_platdata_fbsub
*pd
= fbi
->pdata
->fb_pnl
;
697 control
= readl(ctrl_reg
);
699 if (to
&& (control
& SM501_DC_PANEL_CONTROL_VDD
) == 0) {
700 /* enable panel power */
702 control
|= SM501_DC_PANEL_CONTROL_VDD
; /* FPVDDEN */
703 writel(control
, ctrl_reg
);
704 sm501fb_sync_regs(fbi
);
707 control
|= SM501_DC_PANEL_CONTROL_DATA
; /* DATA */
708 writel(control
, ctrl_reg
);
709 sm501fb_sync_regs(fbi
);
714 if (!(pd
->flags
& SM501FB_FLAG_PANEL_NO_VBIASEN
)) {
715 if (pd
->flags
& SM501FB_FLAG_PANEL_INV_VBIASEN
)
716 control
&= ~SM501_DC_PANEL_CONTROL_BIAS
;
718 control
|= SM501_DC_PANEL_CONTROL_BIAS
;
720 writel(control
, ctrl_reg
);
721 sm501fb_sync_regs(fbi
);
725 if (!(pd
->flags
& SM501FB_FLAG_PANEL_NO_FPEN
)) {
726 if (pd
->flags
& SM501FB_FLAG_PANEL_INV_FPEN
)
727 control
&= ~SM501_DC_PANEL_CONTROL_FPEN
;
729 control
|= SM501_DC_PANEL_CONTROL_FPEN
;
731 writel(control
, ctrl_reg
);
732 sm501fb_sync_regs(fbi
);
735 } else if (!to
&& (control
& SM501_DC_PANEL_CONTROL_VDD
) != 0) {
736 /* disable panel power */
737 if (!(pd
->flags
& SM501FB_FLAG_PANEL_NO_FPEN
)) {
738 if (pd
->flags
& SM501FB_FLAG_PANEL_INV_FPEN
)
739 control
|= SM501_DC_PANEL_CONTROL_FPEN
;
741 control
&= ~SM501_DC_PANEL_CONTROL_FPEN
;
743 writel(control
, ctrl_reg
);
744 sm501fb_sync_regs(fbi
);
748 if (!(pd
->flags
& SM501FB_FLAG_PANEL_NO_VBIASEN
)) {
749 if (pd
->flags
& SM501FB_FLAG_PANEL_INV_VBIASEN
)
750 control
|= SM501_DC_PANEL_CONTROL_BIAS
;
752 control
&= ~SM501_DC_PANEL_CONTROL_BIAS
;
754 writel(control
, ctrl_reg
);
755 sm501fb_sync_regs(fbi
);
759 control
&= ~SM501_DC_PANEL_CONTROL_DATA
;
760 writel(control
, ctrl_reg
);
761 sm501fb_sync_regs(fbi
);
764 control
&= ~SM501_DC_PANEL_CONTROL_VDD
;
765 writel(control
, ctrl_reg
);
766 sm501fb_sync_regs(fbi
);
770 sm501fb_sync_regs(fbi
);
773 /* sm501fb_set_par_pnl
775 * Set the panel video mode from the fb_info structure
778 static int sm501fb_set_par_pnl(struct fb_info
*info
)
780 struct sm501fb_par
*par
= info
->par
;
781 struct sm501fb_info
*fbi
= par
->info
;
782 struct fb_var_screeninfo
*var
= &info
->var
;
783 unsigned long control
;
787 dev_dbg(fbi
->dev
, "%s(%p)\n", __func__
, info
);
789 /* activate this new configuration */
791 ret
= sm501fb_set_par_common(info
, var
);
795 sm501fb_pan_pnl(var
, info
);
796 sm501fb_set_par_geometry(info
, var
);
798 /* update control register */
800 control
= readl(fbi
->regs
+ SM501_DC_PANEL_CONTROL
);
801 control
&= (SM501_DC_PANEL_CONTROL_GAMMA
|
802 SM501_DC_PANEL_CONTROL_VDD
|
803 SM501_DC_PANEL_CONTROL_DATA
|
804 SM501_DC_PANEL_CONTROL_BIAS
|
805 SM501_DC_PANEL_CONTROL_FPEN
|
806 SM501_DC_PANEL_CONTROL_CP
|
807 SM501_DC_PANEL_CONTROL_CK
|
808 SM501_DC_PANEL_CONTROL_HP
|
809 SM501_DC_PANEL_CONTROL_VP
|
810 SM501_DC_PANEL_CONTROL_HPD
|
811 SM501_DC_PANEL_CONTROL_VPD
);
813 control
|= SM501_FIFO_3
; /* fill if >3 free slots */
815 switch(var
->bits_per_pixel
) {
817 control
|= SM501_DC_PANEL_CONTROL_8BPP
;
821 control
|= SM501_DC_PANEL_CONTROL_16BPP
;
822 sm501fb_setup_gamma(fbi
, SM501_DC_PANEL_PALETTE
);
826 control
|= SM501_DC_PANEL_CONTROL_32BPP
;
827 sm501fb_setup_gamma(fbi
, SM501_DC_PANEL_PALETTE
);
834 writel(0x0, fbi
->regs
+ SM501_DC_PANEL_PANNING_CONTROL
);
836 /* panel plane top left and bottom right location */
838 writel(0x00, fbi
->regs
+ SM501_DC_PANEL_TL_LOC
);
841 reg
|= (var
->yres
- 1) << 16;
843 writel(reg
, fbi
->regs
+ SM501_DC_PANEL_BR_LOC
);
845 /* program panel control register */
847 control
|= SM501_DC_PANEL_CONTROL_TE
; /* enable PANEL timing */
848 control
|= SM501_DC_PANEL_CONTROL_EN
; /* enable PANEL gfx plane */
850 if ((var
->sync
& FB_SYNC_HOR_HIGH_ACT
) == 0)
851 control
|= SM501_DC_PANEL_CONTROL_HSP
;
853 if ((var
->sync
& FB_SYNC_VERT_HIGH_ACT
) == 0)
854 control
|= SM501_DC_PANEL_CONTROL_VSP
;
856 writel(control
, fbi
->regs
+ SM501_DC_PANEL_CONTROL
);
857 sm501fb_sync_regs(fbi
);
859 /* ensure the panel interface is not tristated at this point */
861 sm501_modify_reg(fbi
->dev
->parent
, SM501_SYSTEM_CONTROL
,
862 0, SM501_SYSCTRL_PANEL_TRISTATE
);
864 /* power the panel up */
865 sm501fb_panel_power(fbi
, 1);
872 * convert a colour value into a field position
877 static inline unsigned int chan_to_field(unsigned int chan
,
878 struct fb_bitfield
*bf
)
881 chan
>>= 16 - bf
->length
;
882 return chan
<< bf
->offset
;
887 * set the colour mapping for modes that support palettised data
890 static int sm501fb_setcolreg(unsigned regno
,
891 unsigned red
, unsigned green
, unsigned blue
,
892 unsigned transp
, struct fb_info
*info
)
894 struct sm501fb_par
*par
= info
->par
;
895 struct sm501fb_info
*fbi
= par
->info
;
896 void __iomem
*base
= fbi
->regs
;
899 if (par
->head
== HEAD_CRT
)
900 base
+= SM501_DC_CRT_PALETTE
;
902 base
+= SM501_DC_PANEL_PALETTE
;
904 switch (info
->fix
.visual
) {
905 case FB_VISUAL_TRUECOLOR
:
906 /* true-colour, use pseuo-palette */
909 u32
*pal
= par
->pseudo_palette
;
911 val
= chan_to_field(red
, &info
->var
.red
);
912 val
|= chan_to_field(green
, &info
->var
.green
);
913 val
|= chan_to_field(blue
, &info
->var
.blue
);
919 case FB_VISUAL_PSEUDOCOLOR
:
921 val
= (red
>> 8) << 16;
922 val
|= (green
>> 8) << 8;
925 writel(val
, base
+ (regno
* 4));
931 return 1; /* unknown type */
939 * Blank or un-blank the panel interface
942 static int sm501fb_blank_pnl(int blank_mode
, struct fb_info
*info
)
944 struct sm501fb_par
*par
= info
->par
;
945 struct sm501fb_info
*fbi
= par
->info
;
947 dev_dbg(fbi
->dev
, "%s(mode=%d, %p)\n", __func__
, blank_mode
, info
);
949 switch (blank_mode
) {
950 case FB_BLANK_POWERDOWN
:
951 sm501fb_panel_power(fbi
, 0);
954 case FB_BLANK_UNBLANK
:
955 sm501fb_panel_power(fbi
, 1);
958 case FB_BLANK_NORMAL
:
959 case FB_BLANK_VSYNC_SUSPEND
:
960 case FB_BLANK_HSYNC_SUSPEND
:
970 * Blank or un-blank the crt interface
973 static int sm501fb_blank_crt(int blank_mode
, struct fb_info
*info
)
975 struct sm501fb_par
*par
= info
->par
;
976 struct sm501fb_info
*fbi
= par
->info
;
979 dev_dbg(fbi
->dev
, "%s(mode=%d, %p)\n", __func__
, blank_mode
, info
);
981 ctrl
= readl(fbi
->regs
+ SM501_DC_CRT_CONTROL
);
983 switch (blank_mode
) {
984 case FB_BLANK_POWERDOWN
:
985 ctrl
&= ~SM501_DC_CRT_CONTROL_ENABLE
;
986 sm501_misc_control(fbi
->dev
->parent
, SM501_MISC_DAC_POWER
, 0);
988 case FB_BLANK_NORMAL
:
989 ctrl
|= SM501_DC_CRT_CONTROL_BLANK
;
992 case FB_BLANK_UNBLANK
:
993 ctrl
&= ~SM501_DC_CRT_CONTROL_BLANK
;
994 ctrl
|= SM501_DC_CRT_CONTROL_ENABLE
;
995 sm501_misc_control(fbi
->dev
->parent
, 0, SM501_MISC_DAC_POWER
);
998 case FB_BLANK_VSYNC_SUSPEND
:
999 case FB_BLANK_HSYNC_SUSPEND
:
1005 writel(ctrl
, fbi
->regs
+ SM501_DC_CRT_CONTROL
);
1006 sm501fb_sync_regs(fbi
);
1013 * set or change the hardware cursor parameters
1016 static int sm501fb_cursor(struct fb_info
*info
, struct fb_cursor
*cursor
)
1018 struct sm501fb_par
*par
= info
->par
;
1019 struct sm501fb_info
*fbi
= par
->info
;
1020 void __iomem
*base
= fbi
->regs
;
1021 unsigned long hwc_addr
;
1022 unsigned long fg
, bg
;
1024 dev_dbg(fbi
->dev
, "%s(%p,%p)\n", __func__
, info
, cursor
);
1026 if (par
->head
== HEAD_CRT
)
1027 base
+= SM501_DC_CRT_HWC_BASE
;
1029 base
+= SM501_DC_PANEL_HWC_BASE
;
1031 /* check not being asked to exceed capabilities */
1033 if (cursor
->image
.width
> 64)
1036 if (cursor
->image
.height
> 64)
1039 if (cursor
->image
.depth
> 1)
1042 hwc_addr
= readl(base
+ SM501_OFF_HWC_ADDR
);
1045 writel(hwc_addr
| SM501_HWC_EN
, base
+ SM501_OFF_HWC_ADDR
);
1047 writel(hwc_addr
& ~SM501_HWC_EN
, base
+ SM501_OFF_HWC_ADDR
);
1050 if (cursor
->set
& FB_CUR_SETPOS
) {
1051 unsigned int x
= cursor
->image
.dx
;
1052 unsigned int y
= cursor
->image
.dy
;
1054 if (x
>= 2048 || y
>= 2048 )
1057 dev_dbg(fbi
->dev
, "set position %d,%d\n", x
, y
);
1059 //y += cursor->image.height;
1061 writel(x
| (y
<< 16), base
+ SM501_OFF_HWC_LOC
);
1064 if (cursor
->set
& FB_CUR_SETCMAP
) {
1065 unsigned int bg_col
= cursor
->image
.bg_color
;
1066 unsigned int fg_col
= cursor
->image
.fg_color
;
1068 dev_dbg(fbi
->dev
, "%s: update cmap (%08x,%08x)\n",
1069 __func__
, bg_col
, fg_col
);
1071 bg
= ((info
->cmap
.red
[bg_col
] & 0xF8) << 8) |
1072 ((info
->cmap
.green
[bg_col
] & 0xFC) << 3) |
1073 ((info
->cmap
.blue
[bg_col
] & 0xF8) >> 3);
1075 fg
= ((info
->cmap
.red
[fg_col
] & 0xF8) << 8) |
1076 ((info
->cmap
.green
[fg_col
] & 0xFC) << 3) |
1077 ((info
->cmap
.blue
[fg_col
] & 0xF8) >> 3);
1079 dev_dbg(fbi
->dev
, "fgcol %08lx, bgcol %08lx\n", fg
, bg
);
1081 writel(bg
, base
+ SM501_OFF_HWC_COLOR_1_2
);
1082 writel(fg
, base
+ SM501_OFF_HWC_COLOR_3
);
1085 if (cursor
->set
& FB_CUR_SETSIZE
||
1086 cursor
->set
& (FB_CUR_SETIMAGE
| FB_CUR_SETSHAPE
)) {
1087 /* SM501 cursor is a two bpp 64x64 bitmap this routine
1088 * clears it to transparent then combines the cursor
1089 * shape plane with the colour plane to set the
1092 const unsigned char *pcol
= cursor
->image
.data
;
1093 const unsigned char *pmsk
= cursor
->mask
;
1094 void __iomem
*dst
= par
->cursor
.k_addr
;
1095 unsigned char dcol
= 0;
1096 unsigned char dmsk
= 0;
1099 dev_dbg(fbi
->dev
, "%s: setting shape (%d,%d)\n",
1100 __func__
, cursor
->image
.width
, cursor
->image
.height
);
1102 for (op
= 0; op
< (64*64*2)/8; op
+=4)
1103 writel(0x0, dst
+ op
);
1105 for (y
= 0; y
< cursor
->image
.height
; y
++) {
1106 for (x
= 0; x
< cursor
->image
.width
; x
++) {
1116 op
= (dcol
& 1) ? 1 : 3;
1117 op
<<= ((x
% 4) * 2);
1119 op
|= readb(dst
+ (x
/ 4));
1120 writeb(op
, dst
+ (x
/ 4));
1127 sm501fb_sync_regs(fbi
); /* ensure cursor data flushed */
1131 /* sm501fb_crtsrc_show
1133 * device attribute code to show where the crt output is sourced from
1136 static ssize_t
sm501fb_crtsrc_show(struct device
*dev
,
1137 struct device_attribute
*attr
, char *buf
)
1139 struct sm501fb_info
*info
= dev_get_drvdata(dev
);
1142 ctrl
= readl(info
->regs
+ SM501_DC_CRT_CONTROL
);
1143 ctrl
&= SM501_DC_CRT_CONTROL_SEL
;
1145 return snprintf(buf
, PAGE_SIZE
, "%s\n", ctrl
? "crt" : "panel");
1148 /* sm501fb_crtsrc_show
1150 * device attribute code to set where the crt output is sourced from
1153 static ssize_t
sm501fb_crtsrc_store(struct device
*dev
,
1154 struct device_attribute
*attr
,
1155 const char *buf
, size_t len
)
1157 struct sm501fb_info
*info
= dev_get_drvdata(dev
);
1158 enum sm501_controller head
;
1164 if (strnicmp(buf
, "crt", 3) == 0)
1166 else if (strnicmp(buf
, "panel", 5) == 0)
1171 dev_info(dev
, "setting crt source to head %d\n", head
);
1173 ctrl
= readl(info
->regs
+ SM501_DC_CRT_CONTROL
);
1175 if (head
== HEAD_CRT
) {
1176 ctrl
|= SM501_DC_CRT_CONTROL_SEL
;
1177 ctrl
|= SM501_DC_CRT_CONTROL_ENABLE
;
1178 ctrl
|= SM501_DC_CRT_CONTROL_TE
;
1180 ctrl
&= ~SM501_DC_CRT_CONTROL_SEL
;
1181 ctrl
&= ~SM501_DC_CRT_CONTROL_ENABLE
;
1182 ctrl
&= ~SM501_DC_CRT_CONTROL_TE
;
1185 writel(ctrl
, info
->regs
+ SM501_DC_CRT_CONTROL
);
1186 sm501fb_sync_regs(info
);
1191 /* Prepare the device_attr for registration with sysfs later */
1192 static DEVICE_ATTR(crt_src
, 0666, sm501fb_crtsrc_show
, sm501fb_crtsrc_store
);
1194 /* sm501fb_show_regs
1196 * show the primary sm501 registers
1198 static int sm501fb_show_regs(struct sm501fb_info
*info
, char *ptr
,
1199 unsigned int start
, unsigned int len
)
1201 void __iomem
*mem
= info
->regs
;
1205 for (reg
= start
; reg
< (len
+ start
); reg
+= 4)
1206 ptr
+= sprintf(ptr
, "%08x = %08x\n", reg
, readl(mem
+ reg
));
1211 /* sm501fb_debug_show_crt
1213 * show the crt control and cursor registers
1216 static ssize_t
sm501fb_debug_show_crt(struct device
*dev
,
1217 struct device_attribute
*attr
, char *buf
)
1219 struct sm501fb_info
*info
= dev_get_drvdata(dev
);
1222 ptr
+= sm501fb_show_regs(info
, ptr
, SM501_DC_CRT_CONTROL
, 0x40);
1223 ptr
+= sm501fb_show_regs(info
, ptr
, SM501_DC_CRT_HWC_BASE
, 0x10);
1228 static DEVICE_ATTR(fbregs_crt
, 0444, sm501fb_debug_show_crt
, NULL
);
1230 /* sm501fb_debug_show_pnl
1232 * show the panel control and cursor registers
1235 static ssize_t
sm501fb_debug_show_pnl(struct device
*dev
,
1236 struct device_attribute
*attr
, char *buf
)
1238 struct sm501fb_info
*info
= dev_get_drvdata(dev
);
1241 ptr
+= sm501fb_show_regs(info
, ptr
, 0x0, 0x40);
1242 ptr
+= sm501fb_show_regs(info
, ptr
, SM501_DC_PANEL_HWC_BASE
, 0x10);
1247 static DEVICE_ATTR(fbregs_pnl
, 0444, sm501fb_debug_show_pnl
, NULL
);
1249 /* framebuffer ops */
1251 static struct fb_ops sm501fb_ops_crt
= {
1252 .owner
= THIS_MODULE
,
1253 .fb_check_var
= sm501fb_check_var_crt
,
1254 .fb_set_par
= sm501fb_set_par_crt
,
1255 .fb_blank
= sm501fb_blank_crt
,
1256 .fb_setcolreg
= sm501fb_setcolreg
,
1257 .fb_pan_display
= sm501fb_pan_crt
,
1258 .fb_cursor
= sm501fb_cursor
,
1259 .fb_fillrect
= cfb_fillrect
,
1260 .fb_copyarea
= cfb_copyarea
,
1261 .fb_imageblit
= cfb_imageblit
,
1264 static struct fb_ops sm501fb_ops_pnl
= {
1265 .owner
= THIS_MODULE
,
1266 .fb_check_var
= sm501fb_check_var_pnl
,
1267 .fb_set_par
= sm501fb_set_par_pnl
,
1268 .fb_pan_display
= sm501fb_pan_pnl
,
1269 .fb_blank
= sm501fb_blank_pnl
,
1270 .fb_setcolreg
= sm501fb_setcolreg
,
1271 .fb_cursor
= sm501fb_cursor
,
1272 .fb_fillrect
= cfb_fillrect
,
1273 .fb_copyarea
= cfb_copyarea
,
1274 .fb_imageblit
= cfb_imageblit
,
1277 /* sm501_init_cursor
1279 * initialise hw cursor parameters
1282 static int sm501_init_cursor(struct fb_info
*fbi
, unsigned int reg_base
)
1284 struct sm501fb_par
*par
;
1285 struct sm501fb_info
*info
;
1294 par
->cursor_regs
= info
->regs
+ reg_base
;
1296 ret
= sm501_alloc_mem(info
, &par
->cursor
, SM501_MEMF_CURSOR
, 1024,
1301 /* initialise the colour registers */
1303 writel(par
->cursor
.sm_addr
, par
->cursor_regs
+ SM501_OFF_HWC_ADDR
);
1305 writel(0x00, par
->cursor_regs
+ SM501_OFF_HWC_LOC
);
1306 writel(0x00, par
->cursor_regs
+ SM501_OFF_HWC_COLOR_1_2
);
1307 writel(0x00, par
->cursor_regs
+ SM501_OFF_HWC_COLOR_3
);
1308 sm501fb_sync_regs(info
);
1313 /* sm501fb_info_start
1315 * fills the par structure claiming resources and remapping etc.
1318 static int sm501fb_start(struct sm501fb_info
*info
,
1319 struct platform_device
*pdev
)
1321 struct resource
*res
;
1322 struct device
*dev
= &pdev
->dev
;
1326 info
->irq
= ret
= platform_get_irq(pdev
, 0);
1328 /* we currently do not use the IRQ */
1329 dev_warn(dev
, "no irq for device\n");
1332 /* allocate, reserve and remap resources for registers */
1333 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
1335 dev_err(dev
, "no resource definition for registers\n");
1340 info
->regs_res
= request_mem_region(res
->start
,
1341 res
->end
- res
->start
,
1344 if (info
->regs_res
== NULL
) {
1345 dev_err(dev
, "cannot claim registers\n");
1350 info
->regs
= ioremap(res
->start
, (res
->end
- res
->start
)+1);
1351 if (info
->regs
== NULL
) {
1352 dev_err(dev
, "cannot remap registers\n");
1357 /* allocate, reserve resources for framebuffer */
1358 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 2);
1360 dev_err(dev
, "no memory resource defined\n");
1365 info
->fbmem_res
= request_mem_region(res
->start
,
1366 (res
->end
- res
->start
)+1,
1368 if (info
->fbmem_res
== NULL
) {
1369 dev_err(dev
, "cannot claim framebuffer\n");
1374 info
->fbmem
= ioremap(res
->start
, (res
->end
- res
->start
)+1);
1375 if (info
->fbmem
== NULL
) {
1376 dev_err(dev
, "cannot remap framebuffer\n");
1380 info
->fbmem_len
= (res
->end
- res
->start
)+1;
1382 /* clear framebuffer memory - avoids garbage data on unused fb */
1383 memset(info
->fbmem
, 0, info
->fbmem_len
);
1385 /* clear palette ram - undefined at power on */
1386 for (k
= 0; k
< (256 * 3); k
++)
1387 writel(0, info
->regs
+ SM501_DC_PANEL_PALETTE
+ (k
* 4));
1389 /* enable display controller */
1390 sm501_unit_power(dev
->parent
, SM501_GATE_DISPLAY
, 1);
1394 sm501_init_cursor(info
->fb
[HEAD_CRT
], SM501_DC_CRT_HWC_ADDR
);
1395 sm501_init_cursor(info
->fb
[HEAD_PANEL
], SM501_DC_PANEL_HWC_ADDR
);
1397 return 0; /* everything is setup */
1400 release_resource(info
->fbmem_res
);
1401 kfree(info
->fbmem_res
);
1404 iounmap(info
->regs
);
1407 release_resource(info
->regs_res
);
1408 kfree(info
->regs_res
);
1414 static void sm501fb_stop(struct sm501fb_info
*info
)
1416 /* disable display controller */
1417 sm501_unit_power(info
->dev
->parent
, SM501_GATE_DISPLAY
, 0);
1419 iounmap(info
->fbmem
);
1420 release_resource(info
->fbmem_res
);
1421 kfree(info
->fbmem_res
);
1423 iounmap(info
->regs
);
1424 release_resource(info
->regs_res
);
1425 kfree(info
->regs_res
);
1428 static int sm501fb_init_fb(struct fb_info
*fb
,
1429 enum sm501_controller head
,
1432 struct sm501_platdata_fbsub
*pd
;
1433 struct sm501fb_par
*par
= fb
->par
;
1434 struct sm501fb_info
*info
= par
->info
;
1436 unsigned int enable
;
1441 pd
= info
->pdata
->fb_crt
;
1442 ctrl
= readl(info
->regs
+ SM501_DC_CRT_CONTROL
);
1443 enable
= (ctrl
& SM501_DC_CRT_CONTROL_ENABLE
) ? 1 : 0;
1445 /* ensure we set the correct source register */
1446 if (info
->pdata
->fb_route
!= SM501_FB_CRT_PANEL
) {
1447 ctrl
|= SM501_DC_CRT_CONTROL_SEL
;
1448 writel(ctrl
, info
->regs
+ SM501_DC_CRT_CONTROL
);
1454 pd
= info
->pdata
->fb_pnl
;
1455 ctrl
= readl(info
->regs
+ SM501_DC_PANEL_CONTROL
);
1456 enable
= (ctrl
& SM501_DC_PANEL_CONTROL_EN
) ? 1 : 0;
1460 pd
= NULL
; /* stop compiler warnings */
1466 dev_info(info
->dev
, "fb %s %sabled at start\n",
1467 fbname
, enable
? "en" : "dis");
1469 /* check to see if our routing allows this */
1471 if (head
== HEAD_CRT
&& info
->pdata
->fb_route
== SM501_FB_CRT_PANEL
) {
1472 ctrl
&= ~SM501_DC_CRT_CONTROL_SEL
;
1473 writel(ctrl
, info
->regs
+ SM501_DC_CRT_CONTROL
);
1477 strlcpy(fb
->fix
.id
, fbname
, sizeof(fb
->fix
.id
));
1480 (head
== HEAD_CRT
) ? &sm501fb_ops_crt
: &sm501fb_ops_pnl
,
1481 sizeof(struct fb_ops
));
1483 /* update ops dependant on what we've been passed */
1485 if ((pd
->flags
& SM501FB_FLAG_USE_HWCURSOR
) == 0)
1486 par
->ops
.fb_cursor
= NULL
;
1488 fb
->fbops
= &par
->ops
;
1489 fb
->flags
= FBINFO_FLAG_DEFAULT
|
1490 FBINFO_HWACCEL_XPAN
| FBINFO_HWACCEL_YPAN
;
1494 fb
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
1495 fb
->fix
.type_aux
= 0;
1496 fb
->fix
.xpanstep
= 1;
1497 fb
->fix
.ypanstep
= 1;
1498 fb
->fix
.ywrapstep
= 0;
1499 fb
->fix
.accel
= FB_ACCEL_NONE
;
1504 fb
->var
.activate
= FB_ACTIVATE_NOW
;
1505 fb
->var
.accel_flags
= 0;
1506 fb
->var
.vmode
= FB_VMODE_NONINTERLACED
;
1507 fb
->var
.bits_per_pixel
= 16;
1509 if (enable
&& (pd
->flags
& SM501FB_FLAG_USE_INIT_MODE
) && 0) {
1510 /* TODO read the mode from the current display */
1514 dev_info(info
->dev
, "using supplied mode\n");
1515 fb_videomode_to_var(&fb
->var
, pd
->def_mode
);
1517 fb
->var
.bits_per_pixel
= pd
->def_bpp
? pd
->def_bpp
: 8;
1518 fb
->var
.xres_virtual
= fb
->var
.xres
;
1519 fb
->var
.yres_virtual
= fb
->var
.yres
;
1521 ret
= fb_find_mode(&fb
->var
, fb
,
1522 NULL
, NULL
, 0, NULL
, 8);
1524 if (ret
== 0 || ret
== 4) {
1526 "failed to get initial mode\n");
1532 /* initialise and set the palette */
1533 if (fb_alloc_cmap(&fb
->cmap
, NR_PALETTE
, 0)) {
1534 dev_err(info
->dev
, "failed to allocate cmap memory\n");
1537 fb_set_cmap(&fb
->cmap
, fb
);
1539 ret
= (fb
->fbops
->fb_check_var
)(&fb
->var
, fb
);
1541 dev_err(info
->dev
, "check_var() failed on initial setup?\n");
1546 /* default platform data if none is supplied (ie, PCI device) */
1548 static struct sm501_platdata_fbsub sm501fb_pdata_crt
= {
1549 .flags
= (SM501FB_FLAG_USE_INIT_MODE
|
1550 SM501FB_FLAG_USE_HWCURSOR
|
1551 SM501FB_FLAG_USE_HWACCEL
|
1552 SM501FB_FLAG_DISABLE_AT_EXIT
),
1556 static struct sm501_platdata_fbsub sm501fb_pdata_pnl
= {
1557 .flags
= (SM501FB_FLAG_USE_INIT_MODE
|
1558 SM501FB_FLAG_USE_HWCURSOR
|
1559 SM501FB_FLAG_USE_HWACCEL
|
1560 SM501FB_FLAG_DISABLE_AT_EXIT
),
1563 static struct sm501_platdata_fb sm501fb_def_pdata
= {
1564 .fb_route
= SM501_FB_OWN
,
1565 .fb_crt
= &sm501fb_pdata_crt
,
1566 .fb_pnl
= &sm501fb_pdata_pnl
,
1569 static char driver_name_crt
[] = "sm501fb-crt";
1570 static char driver_name_pnl
[] = "sm501fb-panel";
1572 static int __devinit
sm501fb_probe_one(struct sm501fb_info
*info
,
1573 enum sm501_controller head
)
1575 unsigned char *name
= (head
== HEAD_CRT
) ? "crt" : "panel";
1576 struct sm501_platdata_fbsub
*pd
;
1577 struct sm501fb_par
*par
;
1578 struct fb_info
*fbi
;
1580 pd
= (head
== HEAD_CRT
) ? info
->pdata
->fb_crt
: info
->pdata
->fb_pnl
;
1582 /* Do not initialise if we've not been given any platform data */
1584 dev_info(info
->dev
, "no data for fb %s (disabled)\n", name
);
1588 fbi
= framebuffer_alloc(sizeof(struct sm501fb_par
), info
->dev
);
1590 dev_err(info
->dev
, "cannot allocate %s framebuffer\n", name
);
1597 fbi
->pseudo_palette
= &par
->pseudo_palette
;
1599 info
->fb
[head
] = fbi
;
1604 /* Free up anything allocated by sm501fb_init_fb */
1606 static void sm501_free_init_fb(struct sm501fb_info
*info
,
1607 enum sm501_controller head
)
1609 struct fb_info
*fbi
= info
->fb
[head
];
1611 fb_dealloc_cmap(&fbi
->cmap
);
1614 static int __devinit
sm501fb_start_one(struct sm501fb_info
*info
,
1615 enum sm501_controller head
,
1616 const char *drvname
)
1618 struct fb_info
*fbi
= info
->fb
[head
];
1624 mutex_init(&info
->fb
[head
]->mm_lock
);
1626 ret
= sm501fb_init_fb(info
->fb
[head
], head
, drvname
);
1628 dev_err(info
->dev
, "cannot initialise fb %s\n", drvname
);
1632 ret
= register_framebuffer(info
->fb
[head
]);
1634 dev_err(info
->dev
, "failed to register fb %s\n", drvname
);
1635 sm501_free_init_fb(info
, head
);
1639 dev_info(info
->dev
, "fb%d: %s frame buffer\n", fbi
->node
, fbi
->fix
.id
);
1644 static int __devinit
sm501fb_probe(struct platform_device
*pdev
)
1646 struct sm501fb_info
*info
;
1647 struct device
*dev
= &pdev
->dev
;
1650 /* allocate our framebuffers */
1652 info
= kzalloc(sizeof(struct sm501fb_info
), GFP_KERNEL
);
1654 dev_err(dev
, "failed to allocate state\n");
1658 info
->dev
= dev
= &pdev
->dev
;
1659 platform_set_drvdata(pdev
, info
);
1661 if (dev
->parent
->platform_data
) {
1662 struct sm501_platdata
*pd
= dev
->parent
->platform_data
;
1663 info
->pdata
= pd
->fb
;
1666 if (info
->pdata
== NULL
) {
1667 dev_info(dev
, "using default configuration data\n");
1668 info
->pdata
= &sm501fb_def_pdata
;
1671 /* probe for the presence of each panel */
1673 ret
= sm501fb_probe_one(info
, HEAD_CRT
);
1675 dev_err(dev
, "failed to probe CRT\n");
1679 ret
= sm501fb_probe_one(info
, HEAD_PANEL
);
1681 dev_err(dev
, "failed to probe PANEL\n");
1682 goto err_probed_crt
;
1685 if (info
->fb
[HEAD_PANEL
] == NULL
&&
1686 info
->fb
[HEAD_CRT
] == NULL
) {
1687 dev_err(dev
, "no framebuffers found\n");
1691 /* get the resources for both of the framebuffers */
1693 ret
= sm501fb_start(info
, pdev
);
1695 dev_err(dev
, "cannot initialise SM501\n");
1696 goto err_probed_panel
;
1699 ret
= sm501fb_start_one(info
, HEAD_CRT
, driver_name_crt
);
1701 dev_err(dev
, "failed to start CRT\n");
1705 ret
= sm501fb_start_one(info
, HEAD_PANEL
, driver_name_pnl
);
1707 dev_err(dev
, "failed to start Panel\n");
1708 goto err_started_crt
;
1711 /* create device files */
1713 ret
= device_create_file(dev
, &dev_attr_crt_src
);
1715 goto err_started_panel
;
1717 ret
= device_create_file(dev
, &dev_attr_fbregs_pnl
);
1719 goto err_attached_crtsrc_file
;
1721 ret
= device_create_file(dev
, &dev_attr_fbregs_crt
);
1723 goto err_attached_pnlregs_file
;
1725 /* we registered, return ok */
1728 err_attached_pnlregs_file
:
1729 device_remove_file(dev
, &dev_attr_fbregs_pnl
);
1731 err_attached_crtsrc_file
:
1732 device_remove_file(dev
, &dev_attr_crt_src
);
1735 unregister_framebuffer(info
->fb
[HEAD_PANEL
]);
1736 sm501_free_init_fb(info
, HEAD_PANEL
);
1739 unregister_framebuffer(info
->fb
[HEAD_CRT
]);
1740 sm501_free_init_fb(info
, HEAD_CRT
);
1746 framebuffer_release(info
->fb
[HEAD_PANEL
]);
1749 framebuffer_release(info
->fb
[HEAD_CRT
]);
1761 static int sm501fb_remove(struct platform_device
*pdev
)
1763 struct sm501fb_info
*info
= platform_get_drvdata(pdev
);
1764 struct fb_info
*fbinfo_crt
= info
->fb
[0];
1765 struct fb_info
*fbinfo_pnl
= info
->fb
[1];
1767 device_remove_file(&pdev
->dev
, &dev_attr_fbregs_crt
);
1768 device_remove_file(&pdev
->dev
, &dev_attr_fbregs_pnl
);
1769 device_remove_file(&pdev
->dev
, &dev_attr_crt_src
);
1771 sm501_free_init_fb(info
, HEAD_CRT
);
1772 sm501_free_init_fb(info
, HEAD_PANEL
);
1774 unregister_framebuffer(fbinfo_crt
);
1775 unregister_framebuffer(fbinfo_pnl
);
1780 framebuffer_release(fbinfo_pnl
);
1781 framebuffer_release(fbinfo_crt
);
1788 static int sm501fb_suspend_fb(struct sm501fb_info
*info
,
1789 enum sm501_controller head
)
1791 struct fb_info
*fbi
= info
->fb
[head
];
1792 struct sm501fb_par
*par
= fbi
->par
;
1794 if (par
->screen
.size
== 0)
1797 /* blank the relevant interface to ensure unit power minimised */
1798 (par
->ops
.fb_blank
)(FB_BLANK_POWERDOWN
, fbi
);
1800 /* tell console/fb driver we are suspending */
1802 acquire_console_sem();
1803 fb_set_suspend(fbi
, 1);
1804 release_console_sem();
1806 /* backup copies in case chip is powered down over suspend */
1808 par
->store_fb
= vmalloc(par
->screen
.size
);
1809 if (par
->store_fb
== NULL
) {
1810 dev_err(info
->dev
, "no memory to store screen\n");
1814 par
->store_cursor
= vmalloc(par
->cursor
.size
);
1815 if (par
->store_cursor
== NULL
) {
1816 dev_err(info
->dev
, "no memory to store cursor\n");
1820 dev_dbg(info
->dev
, "suspending screen to %p\n", par
->store_fb
);
1821 dev_dbg(info
->dev
, "suspending cursor to %p\n", par
->store_cursor
);
1823 memcpy_fromio(par
->store_fb
, par
->screen
.k_addr
, par
->screen
.size
);
1824 memcpy_fromio(par
->store_cursor
, par
->cursor
.k_addr
, par
->cursor
.size
);
1829 vfree(par
->store_fb
);
1830 par
->store_fb
= NULL
;
1835 static void sm501fb_resume_fb(struct sm501fb_info
*info
,
1836 enum sm501_controller head
)
1838 struct fb_info
*fbi
= info
->fb
[head
];
1839 struct sm501fb_par
*par
= fbi
->par
;
1841 if (par
->screen
.size
== 0)
1844 /* re-activate the configuration */
1846 (par
->ops
.fb_set_par
)(fbi
);
1848 /* restore the data */
1850 dev_dbg(info
->dev
, "restoring screen from %p\n", par
->store_fb
);
1851 dev_dbg(info
->dev
, "restoring cursor from %p\n", par
->store_cursor
);
1854 memcpy_toio(par
->screen
.k_addr
, par
->store_fb
,
1857 if (par
->store_cursor
)
1858 memcpy_toio(par
->cursor
.k_addr
, par
->store_cursor
,
1861 acquire_console_sem();
1862 fb_set_suspend(fbi
, 0);
1863 release_console_sem();
1865 vfree(par
->store_fb
);
1866 vfree(par
->store_cursor
);
1870 /* suspend and resume support */
1872 static int sm501fb_suspend(struct platform_device
*pdev
, pm_message_t state
)
1874 struct sm501fb_info
*info
= platform_get_drvdata(pdev
);
1876 /* store crt control to resume with */
1877 info
->pm_crt_ctrl
= readl(info
->regs
+ SM501_DC_CRT_CONTROL
);
1879 sm501fb_suspend_fb(info
, HEAD_CRT
);
1880 sm501fb_suspend_fb(info
, HEAD_PANEL
);
1882 /* turn off the clocks, in case the device is not powered down */
1883 sm501_unit_power(info
->dev
->parent
, SM501_GATE_DISPLAY
, 0);
1888 #define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP | \
1889 SM501_DC_CRT_CONTROL_SEL)
1892 static int sm501fb_resume(struct platform_device
*pdev
)
1894 struct sm501fb_info
*info
= platform_get_drvdata(pdev
);
1895 unsigned long crt_ctrl
;
1897 sm501_unit_power(info
->dev
->parent
, SM501_GATE_DISPLAY
, 1);
1899 /* restore the items we want to be saved for crt control */
1901 crt_ctrl
= readl(info
->regs
+ SM501_DC_CRT_CONTROL
);
1902 crt_ctrl
&= ~SM501_CRT_CTRL_SAVE
;
1903 crt_ctrl
|= info
->pm_crt_ctrl
& SM501_CRT_CTRL_SAVE
;
1904 writel(crt_ctrl
, info
->regs
+ SM501_DC_CRT_CONTROL
);
1906 sm501fb_resume_fb(info
, HEAD_CRT
);
1907 sm501fb_resume_fb(info
, HEAD_PANEL
);
1913 #define sm501fb_suspend NULL
1914 #define sm501fb_resume NULL
1917 static struct platform_driver sm501fb_driver
= {
1918 .probe
= sm501fb_probe
,
1919 .remove
= sm501fb_remove
,
1920 .suspend
= sm501fb_suspend
,
1921 .resume
= sm501fb_resume
,
1924 .owner
= THIS_MODULE
,
1928 static int __devinit
sm501fb_init(void)
1930 return platform_driver_register(&sm501fb_driver
);
1933 static void __exit
sm501fb_cleanup(void)
1935 platform_driver_unregister(&sm501fb_driver
);
1938 module_init(sm501fb_init
);
1939 module_exit(sm501fb_cleanup
);
1941 MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
1942 MODULE_DESCRIPTION("SM501 Framebuffer driver");
1943 MODULE_LICENSE("GPL v2");