1 // SPDX-License-Identifier: GPL-2.0-only
2 /* linux/drivers/video/sm501fb.c
4 * Copyright (c) 2006 Simtec Electronics
5 * Vincent Sanders <vince@simtec.co.uk>
6 * Ben Dooks <ben@simtec.co.uk>
8 * Framebuffer driver for the Silicon Motion SM501
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/string.h>
16 #include <linux/tty.h>
17 #include <linux/slab.h>
18 #include <linux/delay.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>
31 #include <linux/uaccess.h>
32 #include <asm/div64.h>
38 #include <linux/sm501.h>
39 #include <linux/sm501-regs.h>
43 static char *fb_mode
= "640x480-16@60";
44 static unsigned long default_bpp
= 16;
46 static const struct fb_videomode sm501_default_mode
= {
57 .sync
= FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
58 .vmode
= FB_VMODE_NONINTERLACED
61 #define NR_PALETTE 256
63 enum sm501_controller
{
68 /* SM501 memory address.
70 * This structure is used to track memory usage within the SM501 framebuffer
71 * allocation. The sm_addr field is stored as an offset as it is often used
72 * against both the physical and mapped addresses.
76 unsigned long sm_addr
; /* offset from base of sm501 fb. */
80 /* private data that is shared between all frambuffers* */
83 struct fb_info
*fb
[2]; /* fb info for both heads */
84 struct resource
*fbmem_res
; /* framebuffer resource */
85 struct resource
*regs_res
; /* registers resource */
86 struct resource
*regs2d_res
; /* 2d registers resource */
87 struct sm501_platdata_fb
*pdata
; /* our platform data */
89 unsigned long pm_crt_ctrl
; /* pm: crt ctrl save */
92 int swap_endian
; /* set to swap rgb=>bgr */
93 void __iomem
*regs
; /* remapped registers */
94 void __iomem
*regs2d
; /* 2d remapped registers */
95 void __iomem
*fbmem
; /* remapped framebuffer */
96 size_t fbmem_len
; /* length of remapped region */
100 /* per-framebuffer private data */
102 u32 pseudo_palette
[16];
104 enum sm501_controller head
;
105 struct sm501_mem cursor
;
106 struct sm501_mem screen
;
111 void __iomem
*cursor_regs
;
112 struct sm501fb_info
*info
;
115 /* Helper functions */
117 static inline int h_total(struct fb_var_screeninfo
*var
)
119 return var
->xres
+ var
->left_margin
+
120 var
->right_margin
+ var
->hsync_len
;
123 static inline int v_total(struct fb_var_screeninfo
*var
)
125 return var
->yres
+ var
->upper_margin
+
126 var
->lower_margin
+ var
->vsync_len
;
129 /* sm501fb_sync_regs()
131 * This call is mainly for PCI bus systems where we need to
132 * ensure that any writes to the bus are completed before the
133 * next phase, or after completing a function.
136 static inline void sm501fb_sync_regs(struct sm501fb_info
*info
)
138 smc501_readl(info
->regs
);
143 * This is an attempt to lay out memory for the two framebuffers and
146 * |fbmem_res->start fbmem_res->end|
148 * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K |
149 * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-|
151 * The "spare" space is for the 2d engine data
152 * the fixed is space for the cursors (2x1Kbyte)
154 * we need to allocate memory for the 2D acceleration engine
155 * command list and the data for the engine to deal with.
157 * - all allocations must be 128bit aligned
158 * - cursors are 64x64x2 bits (1Kbyte)
162 #define SM501_MEMF_CURSOR (1)
163 #define SM501_MEMF_PANEL (2)
164 #define SM501_MEMF_CRT (4)
165 #define SM501_MEMF_ACCEL (8)
167 static int sm501_alloc_mem(struct sm501fb_info
*inf
, struct sm501_mem
*mem
,
168 unsigned int why
, size_t size
, u32 smem_len
)
170 struct sm501fb_par
*par
;
176 case SM501_MEMF_CURSOR
:
177 ptr
= inf
->fbmem_len
- size
;
178 inf
->fbmem_len
= ptr
; /* adjust available memory. */
181 case SM501_MEMF_PANEL
:
182 if (size
> inf
->fbmem_len
)
185 ptr
= inf
->fbmem_len
- size
;
186 fbi
= inf
->fb
[HEAD_CRT
];
188 /* round down, some programs such as directfb do not draw
189 * 0,0 correctly unless the start is aligned to a page start.
193 ptr
&= ~(PAGE_SIZE
- 1);
195 if (fbi
&& ptr
< smem_len
)
203 /* check to see if we have panel memory allocated
204 * which would put an limit on available memory. */
206 fbi
= inf
->fb
[HEAD_PANEL
];
209 end
= par
->screen
.k_addr
? par
->screen
.sm_addr
: inf
->fbmem_len
;
211 end
= inf
->fbmem_len
;
213 if ((ptr
+ size
) > end
)
218 case SM501_MEMF_ACCEL
:
219 fbi
= inf
->fb
[HEAD_CRT
];
220 ptr
= fbi
? smem_len
: 0;
222 fbi
= inf
->fb
[HEAD_PANEL
];
225 end
= par
->screen
.sm_addr
;
227 end
= inf
->fbmem_len
;
229 if ((ptr
+ size
) > end
)
240 mem
->k_addr
= inf
->fbmem
+ ptr
;
242 dev_dbg(inf
->dev
, "%s: result %08lx, %p - %u, %zd\n",
243 __func__
, mem
->sm_addr
, mem
->k_addr
, why
, size
);
250 * Converts a period in picoseconds to Hz.
252 * Note, we try to keep this in Hz to minimise rounding with
253 * the limited PLL settings on the SM501.
256 static unsigned long sm501fb_ps_to_hz(unsigned long psvalue
)
258 unsigned long long numerator
=1000000000000ULL;
260 /* 10^12 / picosecond period gives frequency in Hz */
261 do_div(numerator
, psvalue
);
262 return (unsigned long)numerator
;
265 /* sm501fb_hz_to_ps is identical to the opposite transform */
267 #define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x)
269 /* sm501fb_setup_gamma
271 * Programs a linear 1.0 gamma ramp in case the gamma
272 * correction is enabled without programming anything else.
275 static void sm501fb_setup_gamma(struct sm501fb_info
*fbi
,
276 unsigned long palette
)
278 unsigned long value
= 0;
281 /* set gamma values */
282 for (offset
= 0; offset
< 256 * 4; offset
+= 4) {
283 smc501_writel(value
, fbi
->regs
+ palette
+ offset
);
284 value
+= 0x010101; /* Advance RGB by 1,1,1.*/
290 * check common variables for both panel and crt
293 static int sm501fb_check_var(struct fb_var_screeninfo
*var
,
294 struct fb_info
*info
)
296 struct sm501fb_par
*par
= info
->par
;
297 struct sm501fb_info
*sm
= par
->info
;
300 /* check we can fit these values into the registers */
302 if (var
->hsync_len
> 255 || var
->vsync_len
> 63)
305 /* hdisplay end and hsync start */
306 if ((var
->xres
+ var
->right_margin
) > 4096)
309 /* vdisplay end and vsync start */
310 if ((var
->yres
+ var
->lower_margin
) > 2048)
313 /* hard limits of device */
315 if (h_total(var
) > 4096 || v_total(var
) > 2048)
318 /* check our line length is going to be 128 bit aligned */
320 tmp
= (var
->xres
* var
->bits_per_pixel
) / 8;
324 /* check the virtual size */
326 if (var
->xres_virtual
> 4096 || var
->yres_virtual
> 2048)
329 /* can cope with 8,16 or 32bpp */
331 if (var
->bits_per_pixel
<= 8)
332 var
->bits_per_pixel
= 8;
333 else if (var
->bits_per_pixel
<= 16)
334 var
->bits_per_pixel
= 16;
335 else if (var
->bits_per_pixel
== 24)
336 var
->bits_per_pixel
= 32;
338 /* set r/g/b positions and validate bpp */
339 switch(var
->bits_per_pixel
) {
341 var
->red
.length
= var
->bits_per_pixel
;
343 var
->green
.length
= var
->bits_per_pixel
;
344 var
->green
.offset
= 0;
345 var
->blue
.length
= var
->bits_per_pixel
;
346 var
->blue
.offset
= 0;
347 var
->transp
.length
= 0;
348 var
->transp
.offset
= 0;
353 if (sm
->pdata
->flags
& SM501_FBPD_SWAP_FB_ENDIAN
) {
354 var
->blue
.offset
= 11;
355 var
->green
.offset
= 5;
358 var
->red
.offset
= 11;
359 var
->green
.offset
= 5;
360 var
->blue
.offset
= 0;
362 var
->transp
.offset
= 0;
365 var
->green
.length
= 6;
366 var
->blue
.length
= 5;
367 var
->transp
.length
= 0;
371 if (sm
->pdata
->flags
& SM501_FBPD_SWAP_FB_ENDIAN
) {
372 var
->transp
.offset
= 0;
374 var
->green
.offset
= 16;
375 var
->blue
.offset
= 24;
377 var
->transp
.offset
= 24;
378 var
->red
.offset
= 16;
379 var
->green
.offset
= 8;
380 var
->blue
.offset
= 0;
384 var
->green
.length
= 8;
385 var
->blue
.length
= 8;
386 var
->transp
.length
= 0;
397 * sm501fb_check_var_crt():
399 * check the parameters for the CRT head, and either bring them
400 * back into range, or return -EINVAL.
403 static int sm501fb_check_var_crt(struct fb_var_screeninfo
*var
,
404 struct fb_info
*info
)
406 return sm501fb_check_var(var
, info
);
409 /* sm501fb_check_var_pnl():
411 * check the parameters for the CRT head, and either bring them
412 * back into range, or return -EINVAL.
415 static int sm501fb_check_var_pnl(struct fb_var_screeninfo
*var
,
416 struct fb_info
*info
)
418 return sm501fb_check_var(var
, info
);
421 /* sm501fb_set_par_common
423 * set common registers for framebuffers
426 static int sm501fb_set_par_common(struct fb_info
*info
,
427 struct fb_var_screeninfo
*var
)
429 struct sm501fb_par
*par
= info
->par
;
430 struct sm501fb_info
*fbi
= par
->info
;
431 unsigned long pixclock
; /* pixelclock in Hz */
432 unsigned long sm501pixclock
; /* pixelclock the 501 can achieve in Hz */
433 unsigned int mem_type
;
434 unsigned int clock_type
;
435 unsigned int head_addr
;
436 unsigned int smem_len
;
438 dev_dbg(fbi
->dev
, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
439 __func__
, var
->xres
, var
->yres
, var
->bits_per_pixel
,
440 var
->xres_virtual
, var
->yres_virtual
);
444 mem_type
= SM501_MEMF_CRT
;
445 clock_type
= SM501_CLOCK_V2XCLK
;
446 head_addr
= SM501_DC_CRT_FB_ADDR
;
450 mem_type
= SM501_MEMF_PANEL
;
451 clock_type
= SM501_CLOCK_P2XCLK
;
452 head_addr
= SM501_DC_PANEL_FB_ADDR
;
456 mem_type
= 0; /* stop compiler warnings */
461 switch (var
->bits_per_pixel
) {
463 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
467 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
471 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
475 /* allocate fb memory within 501 */
476 info
->fix
.line_length
= (var
->xres_virtual
* var
->bits_per_pixel
)/8;
477 smem_len
= info
->fix
.line_length
* var
->yres_virtual
;
479 dev_dbg(fbi
->dev
, "%s: line length = %u\n", __func__
,
480 info
->fix
.line_length
);
482 if (sm501_alloc_mem(fbi
, &par
->screen
, mem_type
, smem_len
, smem_len
)) {
483 dev_err(fbi
->dev
, "no memory available\n");
487 mutex_lock(&info
->mm_lock
);
488 info
->fix
.smem_start
= fbi
->fbmem_res
->start
+ par
->screen
.sm_addr
;
489 info
->fix
.smem_len
= smem_len
;
490 mutex_unlock(&info
->mm_lock
);
492 info
->screen_base
= fbi
->fbmem
+ par
->screen
.sm_addr
;
493 info
->screen_size
= info
->fix
.smem_len
;
495 /* set start of framebuffer to the screen */
497 smc501_writel(par
->screen
.sm_addr
| SM501_ADDR_FLIP
,
498 fbi
->regs
+ head_addr
);
500 /* program CRT clock */
502 pixclock
= sm501fb_ps_to_hz(var
->pixclock
);
504 sm501pixclock
= sm501_set_clock(fbi
->dev
->parent
, clock_type
,
507 /* update fb layer with actual clock used */
508 var
->pixclock
= sm501fb_hz_to_ps(sm501pixclock
);
510 dev_dbg(fbi
->dev
, "%s: pixclock(ps) = %u, pixclock(Hz) = %lu, "
511 "sm501pixclock = %lu, error = %ld%%\n",
512 __func__
, var
->pixclock
, pixclock
, sm501pixclock
,
513 ((pixclock
- sm501pixclock
)*100)/pixclock
);
518 /* sm501fb_set_par_geometry
520 * set the geometry registers for specified framebuffer.
523 static void sm501fb_set_par_geometry(struct fb_info
*info
,
524 struct fb_var_screeninfo
*var
)
526 struct sm501fb_par
*par
= info
->par
;
527 struct sm501fb_info
*fbi
= par
->info
;
528 void __iomem
*base
= fbi
->regs
;
531 if (par
->head
== HEAD_CRT
)
532 base
+= SM501_DC_CRT_H_TOT
;
534 base
+= SM501_DC_PANEL_H_TOT
;
536 /* set framebuffer width and display width */
538 reg
= info
->fix
.line_length
;
539 reg
|= ((var
->xres
* var
->bits_per_pixel
)/8) << 16;
541 smc501_writel(reg
, fbi
->regs
+ (par
->head
== HEAD_CRT
?
542 SM501_DC_CRT_FB_OFFSET
: SM501_DC_PANEL_FB_OFFSET
));
544 /* program horizontal total */
546 reg
= (h_total(var
) - 1) << 16;
547 reg
|= (var
->xres
- 1);
549 smc501_writel(reg
, base
+ SM501_OFF_DC_H_TOT
);
551 /* program horizontal sync */
553 reg
= var
->hsync_len
<< 16;
554 reg
|= var
->xres
+ var
->right_margin
- 1;
556 smc501_writel(reg
, base
+ SM501_OFF_DC_H_SYNC
);
558 /* program vertical total */
560 reg
= (v_total(var
) - 1) << 16;
561 reg
|= (var
->yres
- 1);
563 smc501_writel(reg
, base
+ SM501_OFF_DC_V_TOT
);
565 /* program vertical sync */
566 reg
= var
->vsync_len
<< 16;
567 reg
|= var
->yres
+ var
->lower_margin
- 1;
569 smc501_writel(reg
, base
+ SM501_OFF_DC_V_SYNC
);
574 * pan the CRT display output within an virtual framebuffer
577 static int sm501fb_pan_crt(struct fb_var_screeninfo
*var
,
578 struct fb_info
*info
)
580 struct sm501fb_par
*par
= info
->par
;
581 struct sm501fb_info
*fbi
= par
->info
;
582 unsigned int bytes_pixel
= info
->var
.bits_per_pixel
/ 8;
586 xoffs
= var
->xoffset
* bytes_pixel
;
588 reg
= smc501_readl(fbi
->regs
+ SM501_DC_CRT_CONTROL
);
590 reg
&= ~SM501_DC_CRT_CONTROL_PIXEL_MASK
;
591 reg
|= ((xoffs
& 15) / bytes_pixel
) << 4;
592 smc501_writel(reg
, fbi
->regs
+ SM501_DC_CRT_CONTROL
);
594 reg
= (par
->screen
.sm_addr
+ xoffs
+
595 var
->yoffset
* info
->fix
.line_length
);
596 smc501_writel(reg
| SM501_ADDR_FLIP
, fbi
->regs
+ SM501_DC_CRT_FB_ADDR
);
598 sm501fb_sync_regs(fbi
);
604 * pan the panel display output within an virtual framebuffer
607 static int sm501fb_pan_pnl(struct fb_var_screeninfo
*var
,
608 struct fb_info
*info
)
610 struct sm501fb_par
*par
= info
->par
;
611 struct sm501fb_info
*fbi
= par
->info
;
614 reg
= var
->xoffset
| (info
->var
.xres_virtual
<< 16);
615 smc501_writel(reg
, fbi
->regs
+ SM501_DC_PANEL_FB_WIDTH
);
617 reg
= var
->yoffset
| (info
->var
.yres_virtual
<< 16);
618 smc501_writel(reg
, fbi
->regs
+ SM501_DC_PANEL_FB_HEIGHT
);
620 sm501fb_sync_regs(fbi
);
624 /* sm501fb_set_par_crt
626 * Set the CRT video mode from the fb_info structure
629 static int sm501fb_set_par_crt(struct fb_info
*info
)
631 struct sm501fb_par
*par
= info
->par
;
632 struct sm501fb_info
*fbi
= par
->info
;
633 struct fb_var_screeninfo
*var
= &info
->var
;
634 unsigned long control
; /* control register */
637 /* activate new configuration */
639 dev_dbg(fbi
->dev
, "%s(%p)\n", __func__
, info
);
641 /* enable CRT DAC - note 0 is on!*/
642 sm501_misc_control(fbi
->dev
->parent
, 0, SM501_MISC_DAC_POWER
);
644 control
= smc501_readl(fbi
->regs
+ SM501_DC_CRT_CONTROL
);
646 control
&= (SM501_DC_CRT_CONTROL_PIXEL_MASK
|
647 SM501_DC_CRT_CONTROL_GAMMA
|
648 SM501_DC_CRT_CONTROL_BLANK
|
649 SM501_DC_CRT_CONTROL_SEL
|
650 SM501_DC_CRT_CONTROL_CP
|
651 SM501_DC_CRT_CONTROL_TVP
);
653 /* set the sync polarities before we check data source */
655 if ((var
->sync
& FB_SYNC_HOR_HIGH_ACT
) == 0)
656 control
|= SM501_DC_CRT_CONTROL_HSP
;
658 if ((var
->sync
& FB_SYNC_VERT_HIGH_ACT
) == 0)
659 control
|= SM501_DC_CRT_CONTROL_VSP
;
661 if ((control
& SM501_DC_CRT_CONTROL_SEL
) == 0) {
662 /* the head is displaying panel data... */
664 sm501_alloc_mem(fbi
, &par
->screen
, SM501_MEMF_CRT
, 0,
669 ret
= sm501fb_set_par_common(info
, var
);
671 dev_err(fbi
->dev
, "failed to set common parameters\n");
675 sm501fb_pan_crt(var
, info
);
676 sm501fb_set_par_geometry(info
, var
);
678 control
|= SM501_FIFO_3
; /* fill if >3 free slots */
680 switch(var
->bits_per_pixel
) {
682 control
|= SM501_DC_CRT_CONTROL_8BPP
;
686 control
|= SM501_DC_CRT_CONTROL_16BPP
;
687 sm501fb_setup_gamma(fbi
, SM501_DC_CRT_PALETTE
);
691 control
|= SM501_DC_CRT_CONTROL_32BPP
;
692 sm501fb_setup_gamma(fbi
, SM501_DC_CRT_PALETTE
);
699 control
|= SM501_DC_CRT_CONTROL_SEL
; /* CRT displays CRT data */
700 control
|= SM501_DC_CRT_CONTROL_TE
; /* enable CRT timing */
701 control
|= SM501_DC_CRT_CONTROL_ENABLE
; /* enable CRT plane */
704 dev_dbg(fbi
->dev
, "new control is %08lx\n", control
);
706 smc501_writel(control
, fbi
->regs
+ SM501_DC_CRT_CONTROL
);
707 sm501fb_sync_regs(fbi
);
712 static void sm501fb_panel_power(struct sm501fb_info
*fbi
, int to
)
714 unsigned long control
;
715 void __iomem
*ctrl_reg
= fbi
->regs
+ SM501_DC_PANEL_CONTROL
;
716 struct sm501_platdata_fbsub
*pd
= fbi
->pdata
->fb_pnl
;
718 control
= smc501_readl(ctrl_reg
);
720 if (to
&& (control
& SM501_DC_PANEL_CONTROL_VDD
) == 0) {
721 /* enable panel power */
723 control
|= SM501_DC_PANEL_CONTROL_VDD
; /* FPVDDEN */
724 smc501_writel(control
, ctrl_reg
);
725 sm501fb_sync_regs(fbi
);
728 control
|= SM501_DC_PANEL_CONTROL_DATA
; /* DATA */
729 smc501_writel(control
, ctrl_reg
);
730 sm501fb_sync_regs(fbi
);
735 if (!(pd
->flags
& SM501FB_FLAG_PANEL_NO_VBIASEN
)) {
736 if (pd
->flags
& SM501FB_FLAG_PANEL_INV_VBIASEN
)
737 control
&= ~SM501_DC_PANEL_CONTROL_BIAS
;
739 control
|= SM501_DC_PANEL_CONTROL_BIAS
;
741 smc501_writel(control
, ctrl_reg
);
742 sm501fb_sync_regs(fbi
);
746 if (!(pd
->flags
& SM501FB_FLAG_PANEL_NO_FPEN
)) {
747 if (pd
->flags
& SM501FB_FLAG_PANEL_INV_FPEN
)
748 control
&= ~SM501_DC_PANEL_CONTROL_FPEN
;
750 control
|= SM501_DC_PANEL_CONTROL_FPEN
;
752 smc501_writel(control
, ctrl_reg
);
753 sm501fb_sync_regs(fbi
);
756 } else if (!to
&& (control
& SM501_DC_PANEL_CONTROL_VDD
) != 0) {
757 /* disable panel power */
758 if (!(pd
->flags
& SM501FB_FLAG_PANEL_NO_FPEN
)) {
759 if (pd
->flags
& SM501FB_FLAG_PANEL_INV_FPEN
)
760 control
|= SM501_DC_PANEL_CONTROL_FPEN
;
762 control
&= ~SM501_DC_PANEL_CONTROL_FPEN
;
764 smc501_writel(control
, ctrl_reg
);
765 sm501fb_sync_regs(fbi
);
769 if (!(pd
->flags
& SM501FB_FLAG_PANEL_NO_VBIASEN
)) {
770 if (pd
->flags
& SM501FB_FLAG_PANEL_INV_VBIASEN
)
771 control
|= SM501_DC_PANEL_CONTROL_BIAS
;
773 control
&= ~SM501_DC_PANEL_CONTROL_BIAS
;
775 smc501_writel(control
, ctrl_reg
);
776 sm501fb_sync_regs(fbi
);
780 control
&= ~SM501_DC_PANEL_CONTROL_DATA
;
781 smc501_writel(control
, ctrl_reg
);
782 sm501fb_sync_regs(fbi
);
785 control
&= ~SM501_DC_PANEL_CONTROL_VDD
;
786 smc501_writel(control
, ctrl_reg
);
787 sm501fb_sync_regs(fbi
);
791 sm501fb_sync_regs(fbi
);
794 /* sm501fb_set_par_pnl
796 * Set the panel video mode from the fb_info structure
799 static int sm501fb_set_par_pnl(struct fb_info
*info
)
801 struct sm501fb_par
*par
= info
->par
;
802 struct sm501fb_info
*fbi
= par
->info
;
803 struct fb_var_screeninfo
*var
= &info
->var
;
804 unsigned long control
;
808 dev_dbg(fbi
->dev
, "%s(%p)\n", __func__
, info
);
810 /* activate this new configuration */
812 ret
= sm501fb_set_par_common(info
, var
);
816 sm501fb_pan_pnl(var
, info
);
817 sm501fb_set_par_geometry(info
, var
);
819 /* update control register */
821 control
= smc501_readl(fbi
->regs
+ SM501_DC_PANEL_CONTROL
);
822 control
&= (SM501_DC_PANEL_CONTROL_GAMMA
|
823 SM501_DC_PANEL_CONTROL_VDD
|
824 SM501_DC_PANEL_CONTROL_DATA
|
825 SM501_DC_PANEL_CONTROL_BIAS
|
826 SM501_DC_PANEL_CONTROL_FPEN
|
827 SM501_DC_PANEL_CONTROL_CP
|
828 SM501_DC_PANEL_CONTROL_CK
|
829 SM501_DC_PANEL_CONTROL_HP
|
830 SM501_DC_PANEL_CONTROL_VP
|
831 SM501_DC_PANEL_CONTROL_HPD
|
832 SM501_DC_PANEL_CONTROL_VPD
);
834 control
|= SM501_FIFO_3
; /* fill if >3 free slots */
836 switch(var
->bits_per_pixel
) {
838 control
|= SM501_DC_PANEL_CONTROL_8BPP
;
842 control
|= SM501_DC_PANEL_CONTROL_16BPP
;
843 sm501fb_setup_gamma(fbi
, SM501_DC_PANEL_PALETTE
);
847 control
|= SM501_DC_PANEL_CONTROL_32BPP
;
848 sm501fb_setup_gamma(fbi
, SM501_DC_PANEL_PALETTE
);
855 smc501_writel(0x0, fbi
->regs
+ SM501_DC_PANEL_PANNING_CONTROL
);
857 /* panel plane top left and bottom right location */
859 smc501_writel(0x00, fbi
->regs
+ SM501_DC_PANEL_TL_LOC
);
862 reg
|= (var
->yres
- 1) << 16;
864 smc501_writel(reg
, fbi
->regs
+ SM501_DC_PANEL_BR_LOC
);
866 /* program panel control register */
868 control
|= SM501_DC_PANEL_CONTROL_TE
; /* enable PANEL timing */
869 control
|= SM501_DC_PANEL_CONTROL_EN
; /* enable PANEL gfx plane */
871 if ((var
->sync
& FB_SYNC_HOR_HIGH_ACT
) == 0)
872 control
|= SM501_DC_PANEL_CONTROL_HSP
;
874 if ((var
->sync
& FB_SYNC_VERT_HIGH_ACT
) == 0)
875 control
|= SM501_DC_PANEL_CONTROL_VSP
;
877 smc501_writel(control
, fbi
->regs
+ SM501_DC_PANEL_CONTROL
);
878 sm501fb_sync_regs(fbi
);
880 /* ensure the panel interface is not tristated at this point */
882 sm501_modify_reg(fbi
->dev
->parent
, SM501_SYSTEM_CONTROL
,
883 0, SM501_SYSCTRL_PANEL_TRISTATE
);
885 /* power the panel up */
886 sm501fb_panel_power(fbi
, 1);
893 * convert a colour value into a field position
898 static inline unsigned int chan_to_field(unsigned int chan
,
899 struct fb_bitfield
*bf
)
902 chan
>>= 16 - bf
->length
;
903 return chan
<< bf
->offset
;
908 * set the colour mapping for modes that support palettised data
911 static int sm501fb_setcolreg(unsigned regno
,
912 unsigned red
, unsigned green
, unsigned blue
,
913 unsigned transp
, struct fb_info
*info
)
915 struct sm501fb_par
*par
= info
->par
;
916 struct sm501fb_info
*fbi
= par
->info
;
917 void __iomem
*base
= fbi
->regs
;
920 if (par
->head
== HEAD_CRT
)
921 base
+= SM501_DC_CRT_PALETTE
;
923 base
+= SM501_DC_PANEL_PALETTE
;
925 switch (info
->fix
.visual
) {
926 case FB_VISUAL_TRUECOLOR
:
927 /* true-colour, use pseuo-palette */
930 u32
*pal
= par
->pseudo_palette
;
932 val
= chan_to_field(red
, &info
->var
.red
);
933 val
|= chan_to_field(green
, &info
->var
.green
);
934 val
|= chan_to_field(blue
, &info
->var
.blue
);
940 case FB_VISUAL_PSEUDOCOLOR
:
942 val
= (red
>> 8) << 16;
943 val
|= (green
>> 8) << 8;
946 smc501_writel(val
, base
+ (regno
* 4));
952 return 1; /* unknown type */
960 * Blank or un-blank the panel interface
963 static int sm501fb_blank_pnl(int blank_mode
, struct fb_info
*info
)
965 struct sm501fb_par
*par
= info
->par
;
966 struct sm501fb_info
*fbi
= par
->info
;
968 dev_dbg(fbi
->dev
, "%s(mode=%d, %p)\n", __func__
, blank_mode
, info
);
970 switch (blank_mode
) {
971 case FB_BLANK_POWERDOWN
:
972 sm501fb_panel_power(fbi
, 0);
975 case FB_BLANK_UNBLANK
:
976 sm501fb_panel_power(fbi
, 1);
979 case FB_BLANK_NORMAL
:
980 case FB_BLANK_VSYNC_SUSPEND
:
981 case FB_BLANK_HSYNC_SUSPEND
:
991 * Blank or un-blank the crt interface
994 static int sm501fb_blank_crt(int blank_mode
, struct fb_info
*info
)
996 struct sm501fb_par
*par
= info
->par
;
997 struct sm501fb_info
*fbi
= par
->info
;
1000 dev_dbg(fbi
->dev
, "%s(mode=%d, %p)\n", __func__
, blank_mode
, info
);
1002 ctrl
= smc501_readl(fbi
->regs
+ SM501_DC_CRT_CONTROL
);
1004 switch (blank_mode
) {
1005 case FB_BLANK_POWERDOWN
:
1006 ctrl
&= ~SM501_DC_CRT_CONTROL_ENABLE
;
1007 sm501_misc_control(fbi
->dev
->parent
, SM501_MISC_DAC_POWER
, 0);
1010 case FB_BLANK_NORMAL
:
1011 ctrl
|= SM501_DC_CRT_CONTROL_BLANK
;
1014 case FB_BLANK_UNBLANK
:
1015 ctrl
&= ~SM501_DC_CRT_CONTROL_BLANK
;
1016 ctrl
|= SM501_DC_CRT_CONTROL_ENABLE
;
1017 sm501_misc_control(fbi
->dev
->parent
, 0, SM501_MISC_DAC_POWER
);
1020 case FB_BLANK_VSYNC_SUSPEND
:
1021 case FB_BLANK_HSYNC_SUSPEND
:
1027 smc501_writel(ctrl
, fbi
->regs
+ SM501_DC_CRT_CONTROL
);
1028 sm501fb_sync_regs(fbi
);
1035 * set or change the hardware cursor parameters
1038 static int sm501fb_cursor(struct fb_info
*info
, struct fb_cursor
*cursor
)
1040 struct sm501fb_par
*par
= info
->par
;
1041 struct sm501fb_info
*fbi
= par
->info
;
1042 void __iomem
*base
= fbi
->regs
;
1043 unsigned long hwc_addr
;
1044 unsigned long fg
, bg
;
1046 dev_dbg(fbi
->dev
, "%s(%p,%p)\n", __func__
, info
, cursor
);
1048 if (par
->head
== HEAD_CRT
)
1049 base
+= SM501_DC_CRT_HWC_BASE
;
1051 base
+= SM501_DC_PANEL_HWC_BASE
;
1053 /* check not being asked to exceed capabilities */
1055 if (cursor
->image
.width
> 64)
1058 if (cursor
->image
.height
> 64)
1061 if (cursor
->image
.depth
> 1)
1064 hwc_addr
= smc501_readl(base
+ SM501_OFF_HWC_ADDR
);
1067 smc501_writel(hwc_addr
| SM501_HWC_EN
,
1068 base
+ SM501_OFF_HWC_ADDR
);
1070 smc501_writel(hwc_addr
& ~SM501_HWC_EN
,
1071 base
+ SM501_OFF_HWC_ADDR
);
1074 if (cursor
->set
& FB_CUR_SETPOS
) {
1075 unsigned int x
= cursor
->image
.dx
;
1076 unsigned int y
= cursor
->image
.dy
;
1078 if (x
>= 2048 || y
>= 2048 )
1081 dev_dbg(fbi
->dev
, "set position %d,%d\n", x
, y
);
1083 //y += cursor->image.height;
1085 smc501_writel(x
| (y
<< 16), base
+ SM501_OFF_HWC_LOC
);
1088 if (cursor
->set
& FB_CUR_SETCMAP
) {
1089 unsigned int bg_col
= cursor
->image
.bg_color
;
1090 unsigned int fg_col
= cursor
->image
.fg_color
;
1092 dev_dbg(fbi
->dev
, "%s: update cmap (%08x,%08x)\n",
1093 __func__
, bg_col
, fg_col
);
1095 bg
= ((info
->cmap
.red
[bg_col
] & 0xF8) << 8) |
1096 ((info
->cmap
.green
[bg_col
] & 0xFC) << 3) |
1097 ((info
->cmap
.blue
[bg_col
] & 0xF8) >> 3);
1099 fg
= ((info
->cmap
.red
[fg_col
] & 0xF8) << 8) |
1100 ((info
->cmap
.green
[fg_col
] & 0xFC) << 3) |
1101 ((info
->cmap
.blue
[fg_col
] & 0xF8) >> 3);
1103 dev_dbg(fbi
->dev
, "fgcol %08lx, bgcol %08lx\n", fg
, bg
);
1105 smc501_writel(bg
, base
+ SM501_OFF_HWC_COLOR_1_2
);
1106 smc501_writel(fg
, base
+ SM501_OFF_HWC_COLOR_3
);
1109 if (cursor
->set
& FB_CUR_SETSIZE
||
1110 cursor
->set
& (FB_CUR_SETIMAGE
| FB_CUR_SETSHAPE
)) {
1111 /* SM501 cursor is a two bpp 64x64 bitmap this routine
1112 * clears it to transparent then combines the cursor
1113 * shape plane with the colour plane to set the
1116 const unsigned char *pcol
= cursor
->image
.data
;
1117 const unsigned char *pmsk
= cursor
->mask
;
1118 void __iomem
*dst
= par
->cursor
.k_addr
;
1119 unsigned char dcol
= 0;
1120 unsigned char dmsk
= 0;
1123 dev_dbg(fbi
->dev
, "%s: setting shape (%d,%d)\n",
1124 __func__
, cursor
->image
.width
, cursor
->image
.height
);
1126 for (op
= 0; op
< (64*64*2)/8; op
+=4)
1127 smc501_writel(0x0, dst
+ op
);
1129 for (y
= 0; y
< cursor
->image
.height
; y
++) {
1130 for (x
= 0; x
< cursor
->image
.width
; x
++) {
1140 op
= (dcol
& 1) ? 1 : 3;
1141 op
<<= ((x
% 4) * 2);
1143 op
|= readb(dst
+ (x
/ 4));
1144 writeb(op
, dst
+ (x
/ 4));
1151 sm501fb_sync_regs(fbi
); /* ensure cursor data flushed */
1155 /* sm501fb_crtsrc_show
1157 * device attribute code to show where the crt output is sourced from
1160 static ssize_t
sm501fb_crtsrc_show(struct device
*dev
,
1161 struct device_attribute
*attr
, char *buf
)
1163 struct sm501fb_info
*info
= dev_get_drvdata(dev
);
1166 ctrl
= smc501_readl(info
->regs
+ SM501_DC_CRT_CONTROL
);
1167 ctrl
&= SM501_DC_CRT_CONTROL_SEL
;
1169 return snprintf(buf
, PAGE_SIZE
, "%s\n", ctrl
? "crt" : "panel");
1172 /* sm501fb_crtsrc_show
1174 * device attribute code to set where the crt output is sourced from
1177 static ssize_t
sm501fb_crtsrc_store(struct device
*dev
,
1178 struct device_attribute
*attr
,
1179 const char *buf
, size_t len
)
1181 struct sm501fb_info
*info
= dev_get_drvdata(dev
);
1182 enum sm501_controller head
;
1188 if (strncasecmp(buf
, "crt", 3) == 0)
1190 else if (strncasecmp(buf
, "panel", 5) == 0)
1195 dev_info(dev
, "setting crt source to head %d\n", head
);
1197 ctrl
= smc501_readl(info
->regs
+ SM501_DC_CRT_CONTROL
);
1199 if (head
== HEAD_CRT
) {
1200 ctrl
|= SM501_DC_CRT_CONTROL_SEL
;
1201 ctrl
|= SM501_DC_CRT_CONTROL_ENABLE
;
1202 ctrl
|= SM501_DC_CRT_CONTROL_TE
;
1204 ctrl
&= ~SM501_DC_CRT_CONTROL_SEL
;
1205 ctrl
&= ~SM501_DC_CRT_CONTROL_ENABLE
;
1206 ctrl
&= ~SM501_DC_CRT_CONTROL_TE
;
1209 smc501_writel(ctrl
, info
->regs
+ SM501_DC_CRT_CONTROL
);
1210 sm501fb_sync_regs(info
);
1215 /* Prepare the device_attr for registration with sysfs later */
1216 static DEVICE_ATTR(crt_src
, 0664, sm501fb_crtsrc_show
, sm501fb_crtsrc_store
);
1218 /* sm501fb_show_regs
1220 * show the primary sm501 registers
1222 static int sm501fb_show_regs(struct sm501fb_info
*info
, char *ptr
,
1223 unsigned int start
, unsigned int len
)
1225 void __iomem
*mem
= info
->regs
;
1229 for (reg
= start
; reg
< (len
+ start
); reg
+= 4)
1230 ptr
+= sprintf(ptr
, "%08x = %08x\n", reg
,
1231 smc501_readl(mem
+ reg
));
1236 /* sm501fb_debug_show_crt
1238 * show the crt control and cursor registers
1241 static ssize_t
sm501fb_debug_show_crt(struct device
*dev
,
1242 struct device_attribute
*attr
, char *buf
)
1244 struct sm501fb_info
*info
= dev_get_drvdata(dev
);
1247 ptr
+= sm501fb_show_regs(info
, ptr
, SM501_DC_CRT_CONTROL
, 0x40);
1248 ptr
+= sm501fb_show_regs(info
, ptr
, SM501_DC_CRT_HWC_BASE
, 0x10);
1253 static DEVICE_ATTR(fbregs_crt
, 0444, sm501fb_debug_show_crt
, NULL
);
1255 /* sm501fb_debug_show_pnl
1257 * show the panel control and cursor registers
1260 static ssize_t
sm501fb_debug_show_pnl(struct device
*dev
,
1261 struct device_attribute
*attr
, char *buf
)
1263 struct sm501fb_info
*info
= dev_get_drvdata(dev
);
1266 ptr
+= sm501fb_show_regs(info
, ptr
, 0x0, 0x40);
1267 ptr
+= sm501fb_show_regs(info
, ptr
, SM501_DC_PANEL_HWC_BASE
, 0x10);
1272 static DEVICE_ATTR(fbregs_pnl
, 0444, sm501fb_debug_show_pnl
, NULL
);
1274 static struct attribute
*sm501fb_attrs
[] = {
1275 &dev_attr_crt_src
.attr
,
1276 &dev_attr_fbregs_pnl
.attr
,
1277 &dev_attr_fbregs_crt
.attr
,
1280 ATTRIBUTE_GROUPS(sm501fb
);
1282 /* acceleration operations */
1283 static int sm501fb_sync(struct fb_info
*info
)
1285 int count
= 1000000;
1286 struct sm501fb_par
*par
= info
->par
;
1287 struct sm501fb_info
*fbi
= par
->info
;
1289 /* wait for the 2d engine to be ready */
1290 while ((count
> 0) &&
1291 (smc501_readl(fbi
->regs
+ SM501_SYSTEM_CONTROL
) &
1292 SM501_SYSCTRL_2D_ENGINE_STATUS
) != 0)
1296 dev_err(info
->dev
, "Timeout waiting for 2d engine sync\n");
1302 static void sm501fb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
1304 struct sm501fb_par
*par
= info
->par
;
1305 struct sm501fb_info
*fbi
= par
->info
;
1306 int width
= area
->width
;
1307 int height
= area
->height
;
1312 unsigned long rtl
= 0;
1315 if ((sx
>= info
->var
.xres_virtual
) ||
1316 (sy
>= info
->var
.yres_virtual
))
1317 /* source Area not within virtual screen, skipping */
1319 if ((sx
+ width
) >= info
->var
.xres_virtual
)
1320 width
= info
->var
.xres_virtual
- sx
- 1;
1321 if ((sy
+ height
) >= info
->var
.yres_virtual
)
1322 height
= info
->var
.yres_virtual
- sy
- 1;
1325 if ((dx
>= info
->var
.xres_virtual
) ||
1326 (dy
>= info
->var
.yres_virtual
))
1327 /* Destination Area not within virtual screen, skipping */
1329 if ((dx
+ width
) >= info
->var
.xres_virtual
)
1330 width
= info
->var
.xres_virtual
- dx
- 1;
1331 if ((dy
+ height
) >= info
->var
.yres_virtual
)
1332 height
= info
->var
.yres_virtual
- dy
- 1;
1334 if ((sx
< dx
) || (sy
< dy
)) {
1342 if (sm501fb_sync(info
))
1345 /* set the base addresses */
1346 smc501_writel(par
->screen
.sm_addr
, fbi
->regs2d
+ SM501_2D_SOURCE_BASE
);
1347 smc501_writel(par
->screen
.sm_addr
,
1348 fbi
->regs2d
+ SM501_2D_DESTINATION_BASE
);
1350 /* set the window width */
1351 smc501_writel((info
->var
.xres
<< 16) | info
->var
.xres
,
1352 fbi
->regs2d
+ SM501_2D_WINDOW_WIDTH
);
1354 /* set window stride */
1355 smc501_writel((info
->var
.xres_virtual
<< 16) | info
->var
.xres_virtual
,
1356 fbi
->regs2d
+ SM501_2D_PITCH
);
1358 /* set data format */
1359 switch (info
->var
.bits_per_pixel
) {
1361 smc501_writel(0, fbi
->regs2d
+ SM501_2D_STRETCH
);
1364 smc501_writel(0x00100000, fbi
->regs2d
+ SM501_2D_STRETCH
);
1367 smc501_writel(0x00200000, fbi
->regs2d
+ SM501_2D_STRETCH
);
1371 /* 2d compare mask */
1372 smc501_writel(0xffffffff, fbi
->regs2d
+ SM501_2D_COLOR_COMPARE_MASK
);
1375 smc501_writel(0xffffffff, fbi
->regs2d
+ SM501_2D_MASK
);
1377 /* source and destination x y */
1378 smc501_writel((sx
<< 16) | sy
, fbi
->regs2d
+ SM501_2D_SOURCE
);
1379 smc501_writel((dx
<< 16) | dy
, fbi
->regs2d
+ SM501_2D_DESTINATION
);
1382 smc501_writel((width
<< 16) | height
, fbi
->regs2d
+ SM501_2D_DIMENSION
);
1385 smc501_writel(0x800000cc | rtl
, fbi
->regs2d
+ SM501_2D_CONTROL
);
1388 static void sm501fb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
1390 struct sm501fb_par
*par
= info
->par
;
1391 struct sm501fb_info
*fbi
= par
->info
;
1392 int width
= rect
->width
, height
= rect
->height
;
1394 if ((rect
->dx
>= info
->var
.xres_virtual
) ||
1395 (rect
->dy
>= info
->var
.yres_virtual
))
1396 /* Rectangle not within virtual screen, skipping */
1398 if ((rect
->dx
+ width
) >= info
->var
.xres_virtual
)
1399 width
= info
->var
.xres_virtual
- rect
->dx
- 1;
1400 if ((rect
->dy
+ height
) >= info
->var
.yres_virtual
)
1401 height
= info
->var
.yres_virtual
- rect
->dy
- 1;
1403 if (sm501fb_sync(info
))
1406 /* set the base addresses */
1407 smc501_writel(par
->screen
.sm_addr
, fbi
->regs2d
+ SM501_2D_SOURCE_BASE
);
1408 smc501_writel(par
->screen
.sm_addr
,
1409 fbi
->regs2d
+ SM501_2D_DESTINATION_BASE
);
1411 /* set the window width */
1412 smc501_writel((info
->var
.xres
<< 16) | info
->var
.xres
,
1413 fbi
->regs2d
+ SM501_2D_WINDOW_WIDTH
);
1415 /* set window stride */
1416 smc501_writel((info
->var
.xres_virtual
<< 16) | info
->var
.xres_virtual
,
1417 fbi
->regs2d
+ SM501_2D_PITCH
);
1419 /* set data format */
1420 switch (info
->var
.bits_per_pixel
) {
1422 smc501_writel(0, fbi
->regs2d
+ SM501_2D_STRETCH
);
1425 smc501_writel(0x00100000, fbi
->regs2d
+ SM501_2D_STRETCH
);
1428 smc501_writel(0x00200000, fbi
->regs2d
+ SM501_2D_STRETCH
);
1432 /* 2d compare mask */
1433 smc501_writel(0xffffffff, fbi
->regs2d
+ SM501_2D_COLOR_COMPARE_MASK
);
1436 smc501_writel(0xffffffff, fbi
->regs2d
+ SM501_2D_MASK
);
1439 smc501_writel(rect
->color
, fbi
->regs2d
+ SM501_2D_FOREGROUND
);
1442 smc501_writel((rect
->dx
<< 16) | rect
->dy
,
1443 fbi
->regs2d
+ SM501_2D_DESTINATION
);
1446 smc501_writel((width
<< 16) | height
, fbi
->regs2d
+ SM501_2D_DIMENSION
);
1448 /* do rectangle fill */
1449 smc501_writel(0x800100cc, fbi
->regs2d
+ SM501_2D_CONTROL
);
1453 static struct fb_ops sm501fb_ops_crt
= {
1454 .owner
= THIS_MODULE
,
1455 .fb_check_var
= sm501fb_check_var_crt
,
1456 .fb_set_par
= sm501fb_set_par_crt
,
1457 .fb_blank
= sm501fb_blank_crt
,
1458 .fb_setcolreg
= sm501fb_setcolreg
,
1459 .fb_pan_display
= sm501fb_pan_crt
,
1460 .fb_cursor
= sm501fb_cursor
,
1461 .fb_fillrect
= sm501fb_fillrect
,
1462 .fb_copyarea
= sm501fb_copyarea
,
1463 .fb_imageblit
= cfb_imageblit
,
1464 .fb_sync
= sm501fb_sync
,
1467 static struct fb_ops sm501fb_ops_pnl
= {
1468 .owner
= THIS_MODULE
,
1469 .fb_check_var
= sm501fb_check_var_pnl
,
1470 .fb_set_par
= sm501fb_set_par_pnl
,
1471 .fb_pan_display
= sm501fb_pan_pnl
,
1472 .fb_blank
= sm501fb_blank_pnl
,
1473 .fb_setcolreg
= sm501fb_setcolreg
,
1474 .fb_cursor
= sm501fb_cursor
,
1475 .fb_fillrect
= sm501fb_fillrect
,
1476 .fb_copyarea
= sm501fb_copyarea
,
1477 .fb_imageblit
= cfb_imageblit
,
1478 .fb_sync
= sm501fb_sync
,
1481 /* sm501_init_cursor
1483 * initialise hw cursor parameters
1486 static int sm501_init_cursor(struct fb_info
*fbi
, unsigned int reg_base
)
1488 struct sm501fb_par
*par
;
1489 struct sm501fb_info
*info
;
1498 par
->cursor_regs
= info
->regs
+ reg_base
;
1500 ret
= sm501_alloc_mem(info
, &par
->cursor
, SM501_MEMF_CURSOR
, 1024,
1505 /* initialise the colour registers */
1507 smc501_writel(par
->cursor
.sm_addr
,
1508 par
->cursor_regs
+ SM501_OFF_HWC_ADDR
);
1510 smc501_writel(0x00, par
->cursor_regs
+ SM501_OFF_HWC_LOC
);
1511 smc501_writel(0x00, par
->cursor_regs
+ SM501_OFF_HWC_COLOR_1_2
);
1512 smc501_writel(0x00, par
->cursor_regs
+ SM501_OFF_HWC_COLOR_3
);
1513 sm501fb_sync_regs(info
);
1518 /* sm501fb_info_start
1520 * fills the par structure claiming resources and remapping etc.
1523 static int sm501fb_start(struct sm501fb_info
*info
,
1524 struct platform_device
*pdev
)
1526 struct resource
*res
;
1527 struct device
*dev
= &pdev
->dev
;
1531 info
->irq
= ret
= platform_get_irq(pdev
, 0);
1533 /* we currently do not use the IRQ */
1534 dev_warn(dev
, "no irq for device\n");
1537 /* allocate, reserve and remap resources for display
1538 * controller registers */
1539 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
1541 dev_err(dev
, "no resource definition for registers\n");
1546 info
->regs_res
= request_mem_region(res
->start
,
1550 if (info
->regs_res
== NULL
) {
1551 dev_err(dev
, "cannot claim registers\n");
1556 info
->regs
= ioremap(res
->start
, resource_size(res
));
1557 if (info
->regs
== NULL
) {
1558 dev_err(dev
, "cannot remap registers\n");
1563 /* allocate, reserve and remap resources for 2d
1564 * controller registers */
1565 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
1567 dev_err(dev
, "no resource definition for 2d registers\n");
1572 info
->regs2d_res
= request_mem_region(res
->start
,
1576 if (info
->regs2d_res
== NULL
) {
1577 dev_err(dev
, "cannot claim registers\n");
1582 info
->regs2d
= ioremap(res
->start
, resource_size(res
));
1583 if (info
->regs2d
== NULL
) {
1584 dev_err(dev
, "cannot remap registers\n");
1586 goto err_regs2d_res
;
1589 /* allocate, reserve resources for framebuffer */
1590 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 2);
1592 dev_err(dev
, "no memory resource defined\n");
1594 goto err_regs2d_map
;
1597 info
->fbmem_res
= request_mem_region(res
->start
,
1600 if (info
->fbmem_res
== NULL
) {
1601 dev_err(dev
, "cannot claim framebuffer\n");
1603 goto err_regs2d_map
;
1606 info
->fbmem
= ioremap(res
->start
, resource_size(res
));
1607 if (info
->fbmem
== NULL
) {
1608 dev_err(dev
, "cannot remap framebuffer\n");
1613 info
->fbmem_len
= resource_size(res
);
1615 /* clear framebuffer memory - avoids garbage data on unused fb */
1616 memset_io(info
->fbmem
, 0, info
->fbmem_len
);
1618 /* clear palette ram - undefined at power on */
1619 for (k
= 0; k
< (256 * 3); k
++)
1620 smc501_writel(0, info
->regs
+ SM501_DC_PANEL_PALETTE
+ (k
* 4));
1622 /* enable display controller */
1623 sm501_unit_power(dev
->parent
, SM501_GATE_DISPLAY
, 1);
1625 /* enable 2d controller */
1626 sm501_unit_power(dev
->parent
, SM501_GATE_2D_ENGINE
, 1);
1629 sm501_init_cursor(info
->fb
[HEAD_CRT
], SM501_DC_CRT_HWC_ADDR
);
1630 sm501_init_cursor(info
->fb
[HEAD_PANEL
], SM501_DC_PANEL_HWC_ADDR
);
1632 return 0; /* everything is setup */
1635 release_mem_region(info
->fbmem_res
->start
,
1636 resource_size(info
->fbmem_res
));
1639 iounmap(info
->regs2d
);
1642 release_mem_region(info
->regs2d_res
->start
,
1643 resource_size(info
->regs2d_res
));
1646 iounmap(info
->regs
);
1649 release_mem_region(info
->regs_res
->start
,
1650 resource_size(info
->regs_res
));
1656 static void sm501fb_stop(struct sm501fb_info
*info
)
1658 /* disable display controller */
1659 sm501_unit_power(info
->dev
->parent
, SM501_GATE_DISPLAY
, 0);
1661 iounmap(info
->fbmem
);
1662 release_mem_region(info
->fbmem_res
->start
,
1663 resource_size(info
->fbmem_res
));
1665 iounmap(info
->regs2d
);
1666 release_mem_region(info
->regs2d_res
->start
,
1667 resource_size(info
->regs2d_res
));
1669 iounmap(info
->regs
);
1670 release_mem_region(info
->regs_res
->start
,
1671 resource_size(info
->regs_res
));
1674 static int sm501fb_init_fb(struct fb_info
*fb
, enum sm501_controller head
,
1677 struct sm501_platdata_fbsub
*pd
;
1678 struct sm501fb_par
*par
= fb
->par
;
1679 struct sm501fb_info
*info
= par
->info
;
1681 unsigned int enable
;
1686 pd
= info
->pdata
->fb_crt
;
1687 ctrl
= smc501_readl(info
->regs
+ SM501_DC_CRT_CONTROL
);
1688 enable
= (ctrl
& SM501_DC_CRT_CONTROL_ENABLE
) ? 1 : 0;
1690 /* ensure we set the correct source register */
1691 if (info
->pdata
->fb_route
!= SM501_FB_CRT_PANEL
) {
1692 ctrl
|= SM501_DC_CRT_CONTROL_SEL
;
1693 smc501_writel(ctrl
, info
->regs
+ SM501_DC_CRT_CONTROL
);
1699 pd
= info
->pdata
->fb_pnl
;
1700 ctrl
= smc501_readl(info
->regs
+ SM501_DC_PANEL_CONTROL
);
1701 enable
= (ctrl
& SM501_DC_PANEL_CONTROL_EN
) ? 1 : 0;
1705 pd
= NULL
; /* stop compiler warnings */
1711 dev_info(info
->dev
, "fb %s %sabled at start\n",
1712 fbname
, enable
? "en" : "dis");
1714 /* check to see if our routing allows this */
1716 if (head
== HEAD_CRT
&& info
->pdata
->fb_route
== SM501_FB_CRT_PANEL
) {
1717 ctrl
&= ~SM501_DC_CRT_CONTROL_SEL
;
1718 smc501_writel(ctrl
, info
->regs
+ SM501_DC_CRT_CONTROL
);
1722 strlcpy(fb
->fix
.id
, fbname
, sizeof(fb
->fix
.id
));
1725 (head
== HEAD_CRT
) ? &sm501fb_ops_crt
: &sm501fb_ops_pnl
,
1726 sizeof(struct fb_ops
));
1728 /* update ops dependent on what we've been passed */
1730 if ((pd
->flags
& SM501FB_FLAG_USE_HWCURSOR
) == 0)
1731 par
->ops
.fb_cursor
= NULL
;
1733 fb
->fbops
= &par
->ops
;
1734 fb
->flags
= FBINFO_FLAG_DEFAULT
| FBINFO_READS_FAST
|
1735 FBINFO_HWACCEL_COPYAREA
| FBINFO_HWACCEL_FILLRECT
|
1736 FBINFO_HWACCEL_XPAN
| FBINFO_HWACCEL_YPAN
;
1738 #if defined(CONFIG_OF)
1740 if (of_get_property(info
->dev
->parent
->of_node
, "little-endian", NULL
))
1741 fb
->flags
|= FBINFO_FOREIGN_ENDIAN
;
1743 if (of_get_property(info
->dev
->parent
->of_node
, "big-endian", NULL
))
1744 fb
->flags
|= FBINFO_FOREIGN_ENDIAN
;
1749 fb
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
1750 fb
->fix
.type_aux
= 0;
1751 fb
->fix
.xpanstep
= 1;
1752 fb
->fix
.ypanstep
= 1;
1753 fb
->fix
.ywrapstep
= 0;
1754 fb
->fix
.accel
= FB_ACCEL_NONE
;
1759 fb
->var
.activate
= FB_ACTIVATE_NOW
;
1760 fb
->var
.accel_flags
= 0;
1761 fb
->var
.vmode
= FB_VMODE_NONINTERLACED
;
1762 fb
->var
.bits_per_pixel
= 16;
1764 if (info
->edid_data
) {
1765 /* Now build modedb from EDID */
1766 fb_edid_to_monspecs(info
->edid_data
, &fb
->monspecs
);
1767 fb_videomode_to_modelist(fb
->monspecs
.modedb
,
1768 fb
->monspecs
.modedb_len
,
1772 if (enable
&& (pd
->flags
& SM501FB_FLAG_USE_INIT_MODE
) && 0) {
1773 /* TODO read the mode from the current display */
1776 dev_info(info
->dev
, "using supplied mode\n");
1777 fb_videomode_to_var(&fb
->var
, pd
->def_mode
);
1779 fb
->var
.bits_per_pixel
= pd
->def_bpp
? pd
->def_bpp
: 8;
1780 fb
->var
.xres_virtual
= fb
->var
.xres
;
1781 fb
->var
.yres_virtual
= fb
->var
.yres
;
1783 if (info
->edid_data
) {
1784 ret
= fb_find_mode(&fb
->var
, fb
, fb_mode
,
1785 fb
->monspecs
.modedb
,
1786 fb
->monspecs
.modedb_len
,
1787 &sm501_default_mode
, default_bpp
);
1788 /* edid_data is no longer needed, free it */
1789 kfree(info
->edid_data
);
1791 ret
= fb_find_mode(&fb
->var
, fb
,
1792 NULL
, NULL
, 0, NULL
, 8);
1797 dev_info(info
->dev
, "using mode specified in "
1801 dev_info(info
->dev
, "using mode specified in "
1802 "@mode with ignored refresh rate\n");
1805 dev_info(info
->dev
, "using mode default "
1809 dev_info(info
->dev
, "using mode from list\n");
1812 dev_info(info
->dev
, "ret = %d\n", ret
);
1813 dev_info(info
->dev
, "failed to find mode\n");
1819 /* initialise and set the palette */
1820 if (fb_alloc_cmap(&fb
->cmap
, NR_PALETTE
, 0)) {
1821 dev_err(info
->dev
, "failed to allocate cmap memory\n");
1824 fb_set_cmap(&fb
->cmap
, fb
);
1826 ret
= (fb
->fbops
->fb_check_var
)(&fb
->var
, fb
);
1828 dev_err(info
->dev
, "check_var() failed on initial setup?\n");
1833 /* default platform data if none is supplied (ie, PCI device) */
1835 static struct sm501_platdata_fbsub sm501fb_pdata_crt
= {
1836 .flags
= (SM501FB_FLAG_USE_INIT_MODE
|
1837 SM501FB_FLAG_USE_HWCURSOR
|
1838 SM501FB_FLAG_USE_HWACCEL
|
1839 SM501FB_FLAG_DISABLE_AT_EXIT
),
1843 static struct sm501_platdata_fbsub sm501fb_pdata_pnl
= {
1844 .flags
= (SM501FB_FLAG_USE_INIT_MODE
|
1845 SM501FB_FLAG_USE_HWCURSOR
|
1846 SM501FB_FLAG_USE_HWACCEL
|
1847 SM501FB_FLAG_DISABLE_AT_EXIT
),
1850 static struct sm501_platdata_fb sm501fb_def_pdata
= {
1851 .fb_route
= SM501_FB_OWN
,
1852 .fb_crt
= &sm501fb_pdata_crt
,
1853 .fb_pnl
= &sm501fb_pdata_pnl
,
1856 static char driver_name_crt
[] = "sm501fb-crt";
1857 static char driver_name_pnl
[] = "sm501fb-panel";
1859 static int sm501fb_probe_one(struct sm501fb_info
*info
,
1860 enum sm501_controller head
)
1862 unsigned char *name
= (head
== HEAD_CRT
) ? "crt" : "panel";
1863 struct sm501_platdata_fbsub
*pd
;
1864 struct sm501fb_par
*par
;
1865 struct fb_info
*fbi
;
1867 pd
= (head
== HEAD_CRT
) ? info
->pdata
->fb_crt
: info
->pdata
->fb_pnl
;
1869 /* Do not initialise if we've not been given any platform data */
1871 dev_info(info
->dev
, "no data for fb %s (disabled)\n", name
);
1875 fbi
= framebuffer_alloc(sizeof(struct sm501fb_par
), info
->dev
);
1882 fbi
->pseudo_palette
= &par
->pseudo_palette
;
1884 info
->fb
[head
] = fbi
;
1889 /* Free up anything allocated by sm501fb_init_fb */
1891 static void sm501_free_init_fb(struct sm501fb_info
*info
,
1892 enum sm501_controller head
)
1894 struct fb_info
*fbi
= info
->fb
[head
];
1899 fb_dealloc_cmap(&fbi
->cmap
);
1902 static int sm501fb_start_one(struct sm501fb_info
*info
,
1903 enum sm501_controller head
, const char *drvname
)
1905 struct fb_info
*fbi
= info
->fb
[head
];
1911 mutex_init(&info
->fb
[head
]->mm_lock
);
1913 ret
= sm501fb_init_fb(info
->fb
[head
], head
, drvname
);
1915 dev_err(info
->dev
, "cannot initialise fb %s\n", drvname
);
1919 ret
= register_framebuffer(info
->fb
[head
]);
1921 dev_err(info
->dev
, "failed to register fb %s\n", drvname
);
1922 sm501_free_init_fb(info
, head
);
1926 dev_info(info
->dev
, "fb%d: %s frame buffer\n", fbi
->node
, fbi
->fix
.id
);
1931 static int sm501fb_probe(struct platform_device
*pdev
)
1933 struct sm501fb_info
*info
;
1934 struct device
*dev
= &pdev
->dev
;
1937 /* allocate our framebuffers */
1938 info
= kzalloc(sizeof(*info
), GFP_KERNEL
);
1940 dev_err(dev
, "failed to allocate state\n");
1944 info
->dev
= dev
= &pdev
->dev
;
1945 platform_set_drvdata(pdev
, info
);
1947 if (dev
->parent
->platform_data
) {
1948 struct sm501_platdata
*pd
= dev
->parent
->platform_data
;
1949 info
->pdata
= pd
->fb
;
1952 if (info
->pdata
== NULL
) {
1954 #if defined(CONFIG_OF)
1955 struct device_node
*np
= pdev
->dev
.parent
->of_node
;
1960 info
->pdata
= &sm501fb_def_pdata
;
1963 cp
= of_get_property(np
, "mode", &len
);
1965 strcpy(fb_mode
, cp
);
1966 prop
= of_get_property(np
, "edid", &len
);
1967 if (prop
&& len
== EDID_LENGTH
) {
1968 info
->edid_data
= kmemdup(prop
, EDID_LENGTH
,
1970 if (info
->edid_data
)
1976 dev_info(dev
, "using default configuration data\n");
1977 info
->pdata
= &sm501fb_def_pdata
;
1981 /* probe for the presence of each panel */
1983 ret
= sm501fb_probe_one(info
, HEAD_CRT
);
1985 dev_err(dev
, "failed to probe CRT\n");
1989 ret
= sm501fb_probe_one(info
, HEAD_PANEL
);
1991 dev_err(dev
, "failed to probe PANEL\n");
1992 goto err_probed_crt
;
1995 if (info
->fb
[HEAD_PANEL
] == NULL
&&
1996 info
->fb
[HEAD_CRT
] == NULL
) {
1997 dev_err(dev
, "no framebuffers found\n");
2002 /* get the resources for both of the framebuffers */
2004 ret
= sm501fb_start(info
, pdev
);
2006 dev_err(dev
, "cannot initialise SM501\n");
2007 goto err_probed_panel
;
2010 ret
= sm501fb_start_one(info
, HEAD_CRT
, driver_name_crt
);
2012 dev_err(dev
, "failed to start CRT\n");
2016 ret
= sm501fb_start_one(info
, HEAD_PANEL
, driver_name_pnl
);
2018 dev_err(dev
, "failed to start Panel\n");
2019 goto err_started_crt
;
2022 /* we registered, return ok */
2026 unregister_framebuffer(info
->fb
[HEAD_CRT
]);
2027 sm501_free_init_fb(info
, HEAD_CRT
);
2033 framebuffer_release(info
->fb
[HEAD_PANEL
]);
2036 framebuffer_release(info
->fb
[HEAD_CRT
]);
2048 static int sm501fb_remove(struct platform_device
*pdev
)
2050 struct sm501fb_info
*info
= platform_get_drvdata(pdev
);
2051 struct fb_info
*fbinfo_crt
= info
->fb
[0];
2052 struct fb_info
*fbinfo_pnl
= info
->fb
[1];
2054 sm501_free_init_fb(info
, HEAD_CRT
);
2055 sm501_free_init_fb(info
, HEAD_PANEL
);
2058 unregister_framebuffer(fbinfo_crt
);
2060 unregister_framebuffer(fbinfo_pnl
);
2065 framebuffer_release(fbinfo_pnl
);
2066 framebuffer_release(fbinfo_crt
);
2073 static int sm501fb_suspend_fb(struct sm501fb_info
*info
,
2074 enum sm501_controller head
)
2076 struct fb_info
*fbi
= info
->fb
[head
];
2077 struct sm501fb_par
*par
;
2083 if (par
->screen
.size
== 0)
2086 /* blank the relevant interface to ensure unit power minimised */
2087 (par
->ops
.fb_blank
)(FB_BLANK_POWERDOWN
, fbi
);
2089 /* tell console/fb driver we are suspending */
2092 fb_set_suspend(fbi
, 1);
2095 /* backup copies in case chip is powered down over suspend */
2097 par
->store_fb
= vmalloc(par
->screen
.size
);
2098 if (par
->store_fb
== NULL
) {
2099 dev_err(info
->dev
, "no memory to store screen\n");
2103 par
->store_cursor
= vmalloc(par
->cursor
.size
);
2104 if (par
->store_cursor
== NULL
) {
2105 dev_err(info
->dev
, "no memory to store cursor\n");
2109 dev_dbg(info
->dev
, "suspending screen to %p\n", par
->store_fb
);
2110 dev_dbg(info
->dev
, "suspending cursor to %p\n", par
->store_cursor
);
2112 memcpy_fromio(par
->store_fb
, par
->screen
.k_addr
, par
->screen
.size
);
2113 memcpy_fromio(par
->store_cursor
, par
->cursor
.k_addr
, par
->cursor
.size
);
2118 vfree(par
->store_fb
);
2119 par
->store_fb
= NULL
;
2124 static void sm501fb_resume_fb(struct sm501fb_info
*info
,
2125 enum sm501_controller head
)
2127 struct fb_info
*fbi
= info
->fb
[head
];
2128 struct sm501fb_par
*par
;
2134 if (par
->screen
.size
== 0)
2137 /* re-activate the configuration */
2139 (par
->ops
.fb_set_par
)(fbi
);
2141 /* restore the data */
2143 dev_dbg(info
->dev
, "restoring screen from %p\n", par
->store_fb
);
2144 dev_dbg(info
->dev
, "restoring cursor from %p\n", par
->store_cursor
);
2147 memcpy_toio(par
->screen
.k_addr
, par
->store_fb
,
2150 if (par
->store_cursor
)
2151 memcpy_toio(par
->cursor
.k_addr
, par
->store_cursor
,
2155 fb_set_suspend(fbi
, 0);
2158 vfree(par
->store_fb
);
2159 vfree(par
->store_cursor
);
2163 /* suspend and resume support */
2165 static int sm501fb_suspend(struct platform_device
*pdev
, pm_message_t state
)
2167 struct sm501fb_info
*info
= platform_get_drvdata(pdev
);
2169 /* store crt control to resume with */
2170 info
->pm_crt_ctrl
= smc501_readl(info
->regs
+ SM501_DC_CRT_CONTROL
);
2172 sm501fb_suspend_fb(info
, HEAD_CRT
);
2173 sm501fb_suspend_fb(info
, HEAD_PANEL
);
2175 /* turn off the clocks, in case the device is not powered down */
2176 sm501_unit_power(info
->dev
->parent
, SM501_GATE_DISPLAY
, 0);
2181 #define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP | \
2182 SM501_DC_CRT_CONTROL_SEL)
2185 static int sm501fb_resume(struct platform_device
*pdev
)
2187 struct sm501fb_info
*info
= platform_get_drvdata(pdev
);
2188 unsigned long crt_ctrl
;
2190 sm501_unit_power(info
->dev
->parent
, SM501_GATE_DISPLAY
, 1);
2192 /* restore the items we want to be saved for crt control */
2194 crt_ctrl
= smc501_readl(info
->regs
+ SM501_DC_CRT_CONTROL
);
2195 crt_ctrl
&= ~SM501_CRT_CTRL_SAVE
;
2196 crt_ctrl
|= info
->pm_crt_ctrl
& SM501_CRT_CTRL_SAVE
;
2197 smc501_writel(crt_ctrl
, info
->regs
+ SM501_DC_CRT_CONTROL
);
2199 sm501fb_resume_fb(info
, HEAD_CRT
);
2200 sm501fb_resume_fb(info
, HEAD_PANEL
);
2206 #define sm501fb_suspend NULL
2207 #define sm501fb_resume NULL
2210 static struct platform_driver sm501fb_driver
= {
2211 .probe
= sm501fb_probe
,
2212 .remove
= sm501fb_remove
,
2213 .suspend
= sm501fb_suspend
,
2214 .resume
= sm501fb_resume
,
2217 .dev_groups
= sm501fb_groups
,
2221 module_platform_driver(sm501fb_driver
);
2223 module_param_named(mode
, fb_mode
, charp
, 0);
2224 MODULE_PARM_DESC(mode
,
2225 "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
2226 module_param_named(bpp
, default_bpp
, ulong
, 0);
2227 MODULE_PARM_DESC(bpp
, "Specify bit-per-pixel if not specified mode");
2228 MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
2229 MODULE_DESCRIPTION("SM501 Framebuffer driver");
2230 MODULE_LICENSE("GPL v2");