2009-04-01 02:25:39 +04:00
/* linux/drivers/video/s3c-fb.c
*
* Copyright 2008 Openmoko Inc .
* Copyright 2008 Simtec Electronics
* Ben Dooks < ben @ simtec . co . uk >
* http : //armlinux.simtec.co.uk/
*
* Samsung SoC Framebuffer driver
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/dma-mapping.h>
# include <linux/init.h>
# include <linux/gfp.h>
# include <linux/clk.h>
# include <linux/fb.h>
# include <linux/io.h>
# include <mach/map.h>
# include <mach/regs-fb.h>
# include <plat/fb.h>
/* This driver will export a number of framebuffer interfaces depending
* on the configuration passed in via the platform data . Each fb instance
* maps to a hardware window . Currently there is no support for runtime
* setting of the alpha - blending functions that each window has , so only
* window 0 is actually useful .
*
* Window 0 is treated specially , it is used for the basis of the LCD
* output timings and as the control for the output power - down state .
*/
/* note, some of the functions that get called are derived from including
* < mach / regs - fb . h > as they are specific to the architecture that the code
* is being built for .
*/
# ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
# undef writel
# define writel(v, r) do { \
printk ( KERN_DEBUG " %s: %08x => %p \n " , __func__ , ( unsigned int ) v , r ) ; \
__raw_writel ( v , r ) ; } while ( 0 )
# endif /* FB_S3C_DEBUG_REGWRITE */
struct s3c_fb ;
/**
* struct s3c_fb_win - per window private data for each framebuffer .
* @ windata : The platform data supplied for the window configuration .
* @ parent : The hardware that this window is part of .
* @ fbinfo : Pointer pack to the framebuffer info for this window .
* @ palette_buffer : Buffer / cache to hold palette entries .
* @ pseudo_palette : For use in TRUECOLOUR modes for entries 0. .15 /
* @ index : The window number of this window .
* @ palette : The bitfields for changing r / g / b into a hardware palette entry .
*/
struct s3c_fb_win {
struct s3c_fb_pd_win * windata ;
struct s3c_fb * parent ;
struct fb_info * fbinfo ;
struct s3c_fb_palette palette ;
u32 * palette_buffer ;
u32 pseudo_palette [ 16 ] ;
unsigned int index ;
} ;
/**
* struct s3c_fb - overall hardware state of the hardware
* @ dev : The device that we bound to , for printing , etc .
* @ regs_res : The resource we claimed for the IO registers .
* @ bus_clk : The clk ( hclk ) feeding our interface and possibly pixclk .
* @ regs : The mapped hardware registers .
* @ enabled : A bitmask of enabled hardware windows .
* @ pdata : The platform configuration data passed with the device .
* @ windows : The hardware windows that have been claimed .
*/
struct s3c_fb {
struct device * dev ;
struct resource * regs_res ;
struct clk * bus_clk ;
void __iomem * regs ;
unsigned char enabled ;
struct s3c_fb_platdata * pdata ;
struct s3c_fb_win * windows [ S3C_FB_MAX_WIN ] ;
} ;
/**
* s3c_fb_win_has_palette ( ) - determine if a mode has a palette
* @ win : The window number being queried .
* @ bpp : The number of bits per pixel to test .
*
* Work out if the given window supports palletised data at the specified bpp .
*/
static int s3c_fb_win_has_palette ( unsigned int win , unsigned int bpp )
{
return s3c_fb_win_pal_size ( win ) < = ( 1 < < bpp ) ;
}
/**
* s3c_fb_check_var ( ) - framebuffer layer request to verify a given mode .
* @ var : The screen information to verify .
* @ info : The framebuffer device .
*
* Framebuffer layer call to verify the given information and allow us to
* update various information depending on the hardware capabilities .
*/
static int s3c_fb_check_var ( struct fb_var_screeninfo * var ,
struct fb_info * info )
{
struct s3c_fb_win * win = info - > par ;
struct s3c_fb_pd_win * windata = win - > windata ;
struct s3c_fb * sfb = win - > parent ;
dev_dbg ( sfb - > dev , " checking parameters \n " ) ;
var - > xres_virtual = max ( ( unsigned int ) windata - > virtual_x , var - > xres ) ;
var - > yres_virtual = max ( ( unsigned int ) windata - > virtual_y , var - > yres ) ;
if ( ! s3c_fb_validate_win_bpp ( win - > index , var - > bits_per_pixel ) ) {
dev_dbg ( sfb - > dev , " win %d: unsupported bpp %d \n " ,
win - > index , var - > bits_per_pixel ) ;
return - EINVAL ;
}
/* always ensure these are zero, for drop through cases below */
var - > transp . offset = 0 ;
var - > transp . length = 0 ;
switch ( var - > bits_per_pixel ) {
case 1 :
case 2 :
case 4 :
case 8 :
if ( ! s3c_fb_win_has_palette ( win - > index , var - > bits_per_pixel ) ) {
/* non palletised, A:1,R:2,G:3,B:2 mode */
var - > red . offset = 4 ;
var - > green . offset = 2 ;
var - > blue . offset = 0 ;
var - > red . length = 5 ;
var - > green . length = 3 ;
var - > blue . length = 2 ;
var - > transp . offset = 7 ;
var - > transp . length = 1 ;
} else {
var - > red . offset = 0 ;
var - > red . length = var - > bits_per_pixel ;
var - > green = var - > red ;
var - > blue = var - > red ;
}
break ;
case 19 :
/* 666 with one bit alpha/transparency */
var - > transp . offset = 18 ;
var - > transp . length = 1 ;
case 18 :
var - > bits_per_pixel = 32 ;
/* 666 format */
var - > red . offset = 12 ;
var - > green . offset = 6 ;
var - > blue . offset = 0 ;
var - > red . length = 6 ;
var - > green . length = 6 ;
var - > blue . length = 6 ;
break ;
case 16 :
/* 16 bpp, 565 format */
var - > red . offset = 11 ;
var - > green . offset = 5 ;
var - > blue . offset = 0 ;
var - > red . length = 5 ;
var - > green . length = 6 ;
var - > blue . length = 5 ;
break ;
case 28 :
case 25 :
var - > transp . length = var - > bits_per_pixel - 24 ;
var - > transp . offset = 24 ;
/* drop through */
case 24 :
/* our 24bpp is unpacked, so 32bpp */
var - > bits_per_pixel = 32 ;
case 32 :
var - > red . offset = 16 ;
var - > red . length = 8 ;
var - > green . offset = 8 ;
var - > green . length = 8 ;
var - > blue . offset = 0 ;
var - > blue . length = 8 ;
break ;
default :
dev_err ( sfb - > dev , " invalid bpp \n " ) ;
}
dev_dbg ( sfb - > dev , " %s: verified parameters \n " , __func__ ) ;
return 0 ;
}
/**
* s3c_fb_calc_pixclk ( ) - calculate the divider to create the pixel clock .
drivers/video/s3c-fb.c: fix clock setting for Samsung SoC Framebuffer
Correct the CLKVAL_F field value of VIDEO MAIN CONTROLLER 0 REGITSTER.
Frame Rate is 1 / [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1)
} x {(HSPW+1) + (HBPD +1)
+ (HFPD+1) + (HOZVAL + 1) } x { ( CLKVAL+1 ) / ( Frequency of Clock
source ) } ] and VCLK = Video Clock Source / (CLKVAL +1).
therefore CLKVAL_F should be "CLKVAL_F = Frequency of Clock source / pixel
clock * refresh".
for this, I added refresh value in platform data like below.
static struct s3c_fb_pd_win xxx_fb_win0 = {
/* this is to ensure we use win0 */
.win_mode = {
.refresh = 60,
.pixclock = (66+4+2+480)*(15+5+3+800),
.left_margin = 66,
.right_margin = 2,
.upper_margin = 15,
.lower_margin = 3,
.hsync_len = 4,
.vsync_len = 5,
.xres = 480,
.yres = 800,
},
.max_bpp = 32,
.default_bpp = 24,
};
static struct s3c_fb_platdata xxx_lcd_pdata __initdata = {
.win[0] = &xxx_fb_win0,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC
| VIDCON1_INV_VCLK | VIDCON1_INV_VDEN,
.setup_gpio = s5pc1xx_fb_gpio_setup_24bpp,
};
xxx_machine_init()
{
.
.
.
s3c_fb_set_platdata(&xxx_lcd_pdata);
}
platform data defined in machine code should be setting using
s3c_fb_set_platdata().
Signed-off-by: InKi Dae <inki.dae@samsung.com>
Cc: Kyungmin Park <kmpark@infradead.org>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-07-05 23:08:21 +04:00
* @ id : window id .
2009-04-01 02:25:39 +04:00
* @ sfb : The hardware state .
* @ pixclock : The pixel clock wanted , in picoseconds .
*
* Given the specified pixel clock , work out the necessary divider to get
* close to the output frequency .
*/
drivers/video/s3c-fb.c: fix clock setting for Samsung SoC Framebuffer
Correct the CLKVAL_F field value of VIDEO MAIN CONTROLLER 0 REGITSTER.
Frame Rate is 1 / [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1)
} x {(HSPW+1) + (HBPD +1)
+ (HFPD+1) + (HOZVAL + 1) } x { ( CLKVAL+1 ) / ( Frequency of Clock
source ) } ] and VCLK = Video Clock Source / (CLKVAL +1).
therefore CLKVAL_F should be "CLKVAL_F = Frequency of Clock source / pixel
clock * refresh".
for this, I added refresh value in platform data like below.
static struct s3c_fb_pd_win xxx_fb_win0 = {
/* this is to ensure we use win0 */
.win_mode = {
.refresh = 60,
.pixclock = (66+4+2+480)*(15+5+3+800),
.left_margin = 66,
.right_margin = 2,
.upper_margin = 15,
.lower_margin = 3,
.hsync_len = 4,
.vsync_len = 5,
.xres = 480,
.yres = 800,
},
.max_bpp = 32,
.default_bpp = 24,
};
static struct s3c_fb_platdata xxx_lcd_pdata __initdata = {
.win[0] = &xxx_fb_win0,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC
| VIDCON1_INV_VCLK | VIDCON1_INV_VDEN,
.setup_gpio = s5pc1xx_fb_gpio_setup_24bpp,
};
xxx_machine_init()
{
.
.
.
s3c_fb_set_platdata(&xxx_lcd_pdata);
}
platform data defined in machine code should be setting using
s3c_fb_set_platdata().
Signed-off-by: InKi Dae <inki.dae@samsung.com>
Cc: Kyungmin Park <kmpark@infradead.org>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-07-05 23:08:21 +04:00
static int s3c_fb_calc_pixclk ( unsigned char id , struct s3c_fb * sfb , unsigned int pixclk )
2009-04-01 02:25:39 +04:00
{
drivers/video/s3c-fb.c: fix clock setting for Samsung SoC Framebuffer
Correct the CLKVAL_F field value of VIDEO MAIN CONTROLLER 0 REGITSTER.
Frame Rate is 1 / [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1)
} x {(HSPW+1) + (HBPD +1)
+ (HFPD+1) + (HOZVAL + 1) } x { ( CLKVAL+1 ) / ( Frequency of Clock
source ) } ] and VCLK = Video Clock Source / (CLKVAL +1).
therefore CLKVAL_F should be "CLKVAL_F = Frequency of Clock source / pixel
clock * refresh".
for this, I added refresh value in platform data like below.
static struct s3c_fb_pd_win xxx_fb_win0 = {
/* this is to ensure we use win0 */
.win_mode = {
.refresh = 60,
.pixclock = (66+4+2+480)*(15+5+3+800),
.left_margin = 66,
.right_margin = 2,
.upper_margin = 15,
.lower_margin = 3,
.hsync_len = 4,
.vsync_len = 5,
.xres = 480,
.yres = 800,
},
.max_bpp = 32,
.default_bpp = 24,
};
static struct s3c_fb_platdata xxx_lcd_pdata __initdata = {
.win[0] = &xxx_fb_win0,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC
| VIDCON1_INV_VCLK | VIDCON1_INV_VDEN,
.setup_gpio = s5pc1xx_fb_gpio_setup_24bpp,
};
xxx_machine_init()
{
.
.
.
s3c_fb_set_platdata(&xxx_lcd_pdata);
}
platform data defined in machine code should be setting using
s3c_fb_set_platdata().
Signed-off-by: InKi Dae <inki.dae@samsung.com>
Cc: Kyungmin Park <kmpark@infradead.org>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-07-05 23:08:21 +04:00
struct s3c_fb_pd_win * win = sfb - > pdata - > win [ id ] ;
2009-04-01 02:25:39 +04:00
unsigned long clk = clk_get_rate ( sfb - > bus_clk ) ;
unsigned int result ;
drivers/video/s3c-fb.c: fix clock setting for Samsung SoC Framebuffer
Correct the CLKVAL_F field value of VIDEO MAIN CONTROLLER 0 REGITSTER.
Frame Rate is 1 / [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1)
} x {(HSPW+1) + (HBPD +1)
+ (HFPD+1) + (HOZVAL + 1) } x { ( CLKVAL+1 ) / ( Frequency of Clock
source ) } ] and VCLK = Video Clock Source / (CLKVAL +1).
therefore CLKVAL_F should be "CLKVAL_F = Frequency of Clock source / pixel
clock * refresh".
for this, I added refresh value in platform data like below.
static struct s3c_fb_pd_win xxx_fb_win0 = {
/* this is to ensure we use win0 */
.win_mode = {
.refresh = 60,
.pixclock = (66+4+2+480)*(15+5+3+800),
.left_margin = 66,
.right_margin = 2,
.upper_margin = 15,
.lower_margin = 3,
.hsync_len = 4,
.vsync_len = 5,
.xres = 480,
.yres = 800,
},
.max_bpp = 32,
.default_bpp = 24,
};
static struct s3c_fb_platdata xxx_lcd_pdata __initdata = {
.win[0] = &xxx_fb_win0,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC
| VIDCON1_INV_VCLK | VIDCON1_INV_VDEN,
.setup_gpio = s5pc1xx_fb_gpio_setup_24bpp,
};
xxx_machine_init()
{
.
.
.
s3c_fb_set_platdata(&xxx_lcd_pdata);
}
platform data defined in machine code should be setting using
s3c_fb_set_platdata().
Signed-off-by: InKi Dae <inki.dae@samsung.com>
Cc: Kyungmin Park <kmpark@infradead.org>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-07-05 23:08:21 +04:00
pixclk * = win - > win_mode . refresh ;
result = clk / pixclk ;
2009-04-01 02:25:39 +04:00
dev_dbg ( sfb - > dev , " pixclk=%u, clk=%lu, div=%d (%lu) \n " ,
pixclk , clk , result , clk / result ) ;
return result ;
}
/**
* s3c_fb_align_word ( ) - align pixel count to word boundary
* @ bpp : The number of bits per pixel
* @ pix : The value to be aligned .
*
* Align the given pixel count so that it will start on an 32 bit word
* boundary .
*/
static int s3c_fb_align_word ( unsigned int bpp , unsigned int pix )
{
int pix_per_word ;
if ( bpp > 16 )
return pix ;
pix_per_word = ( 8 * 32 ) / bpp ;
return ALIGN ( pix , pix_per_word ) ;
}
/**
* s3c_fb_set_par ( ) - framebuffer request to set new framebuffer state .
* @ info : The framebuffer to change .
*
* Framebuffer layer request to set a new mode for the specified framebuffer
*/
static int s3c_fb_set_par ( struct fb_info * info )
{
struct fb_var_screeninfo * var = & info - > var ;
struct s3c_fb_win * win = info - > par ;
struct s3c_fb * sfb = win - > parent ;
void __iomem * regs = sfb - > regs ;
int win_no = win - > index ;
drivers/video/s3c-fb.c: fix clock setting for Samsung SoC Framebuffer
Correct the CLKVAL_F field value of VIDEO MAIN CONTROLLER 0 REGITSTER.
Frame Rate is 1 / [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1)
} x {(HSPW+1) + (HBPD +1)
+ (HFPD+1) + (HOZVAL + 1) } x { ( CLKVAL+1 ) / ( Frequency of Clock
source ) } ] and VCLK = Video Clock Source / (CLKVAL +1).
therefore CLKVAL_F should be "CLKVAL_F = Frequency of Clock source / pixel
clock * refresh".
for this, I added refresh value in platform data like below.
static struct s3c_fb_pd_win xxx_fb_win0 = {
/* this is to ensure we use win0 */
.win_mode = {
.refresh = 60,
.pixclock = (66+4+2+480)*(15+5+3+800),
.left_margin = 66,
.right_margin = 2,
.upper_margin = 15,
.lower_margin = 3,
.hsync_len = 4,
.vsync_len = 5,
.xres = 480,
.yres = 800,
},
.max_bpp = 32,
.default_bpp = 24,
};
static struct s3c_fb_platdata xxx_lcd_pdata __initdata = {
.win[0] = &xxx_fb_win0,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC
| VIDCON1_INV_VCLK | VIDCON1_INV_VDEN,
.setup_gpio = s5pc1xx_fb_gpio_setup_24bpp,
};
xxx_machine_init()
{
.
.
.
s3c_fb_set_platdata(&xxx_lcd_pdata);
}
platform data defined in machine code should be setting using
s3c_fb_set_platdata().
Signed-off-by: InKi Dae <inki.dae@samsung.com>
Cc: Kyungmin Park <kmpark@infradead.org>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-07-05 23:08:21 +04:00
u32 osdc_data = 0 ;
2009-04-01 02:25:39 +04:00
u32 data ;
u32 pagewidth ;
int clkdiv ;
dev_dbg ( sfb - > dev , " setting framebuffer parameters \n " ) ;
switch ( var - > bits_per_pixel ) {
case 32 :
case 24 :
case 16 :
case 12 :
info - > fix . visual = FB_VISUAL_TRUECOLOR ;
break ;
case 8 :
if ( s3c_fb_win_has_palette ( win_no , 8 ) )
info - > fix . visual = FB_VISUAL_PSEUDOCOLOR ;
else
info - > fix . visual = FB_VISUAL_TRUECOLOR ;
break ;
case 1 :
info - > fix . visual = FB_VISUAL_MONO01 ;
break ;
default :
info - > fix . visual = FB_VISUAL_PSEUDOCOLOR ;
break ;
}
info - > fix . line_length = ( var - > xres_virtual * var - > bits_per_pixel ) / 8 ;
/* disable the window whilst we update it */
writel ( 0 , regs + WINCON ( win_no ) ) ;
/* use window 0 as the basis for the lcd output timings */
if ( win_no = = 0 ) {
drivers/video/s3c-fb.c: fix clock setting for Samsung SoC Framebuffer
Correct the CLKVAL_F field value of VIDEO MAIN CONTROLLER 0 REGITSTER.
Frame Rate is 1 / [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1)
} x {(HSPW+1) + (HBPD +1)
+ (HFPD+1) + (HOZVAL + 1) } x { ( CLKVAL+1 ) / ( Frequency of Clock
source ) } ] and VCLK = Video Clock Source / (CLKVAL +1).
therefore CLKVAL_F should be "CLKVAL_F = Frequency of Clock source / pixel
clock * refresh".
for this, I added refresh value in platform data like below.
static struct s3c_fb_pd_win xxx_fb_win0 = {
/* this is to ensure we use win0 */
.win_mode = {
.refresh = 60,
.pixclock = (66+4+2+480)*(15+5+3+800),
.left_margin = 66,
.right_margin = 2,
.upper_margin = 15,
.lower_margin = 3,
.hsync_len = 4,
.vsync_len = 5,
.xres = 480,
.yres = 800,
},
.max_bpp = 32,
.default_bpp = 24,
};
static struct s3c_fb_platdata xxx_lcd_pdata __initdata = {
.win[0] = &xxx_fb_win0,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC
| VIDCON1_INV_VCLK | VIDCON1_INV_VDEN,
.setup_gpio = s5pc1xx_fb_gpio_setup_24bpp,
};
xxx_machine_init()
{
.
.
.
s3c_fb_set_platdata(&xxx_lcd_pdata);
}
platform data defined in machine code should be setting using
s3c_fb_set_platdata().
Signed-off-by: InKi Dae <inki.dae@samsung.com>
Cc: Kyungmin Park <kmpark@infradead.org>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-07-05 23:08:21 +04:00
clkdiv = s3c_fb_calc_pixclk ( win_no , sfb , var - > pixclock ) ;
2009-04-01 02:25:39 +04:00
data = sfb - > pdata - > vidcon0 ;
data & = ~ ( VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR ) ;
if ( clkdiv > 1 )
data | = VIDCON0_CLKVAL_F ( clkdiv - 1 ) | VIDCON0_CLKDIR ;
else
data & = ~ VIDCON0_CLKDIR ; /* 1:1 clock */
/* write the timing data to the panel */
data | = VIDCON0_ENVID | VIDCON0_ENVID_F ;
writel ( data , regs + VIDCON0 ) ;
data = VIDTCON0_VBPD ( var - > upper_margin - 1 ) |
VIDTCON0_VFPD ( var - > lower_margin - 1 ) |
VIDTCON0_VSPW ( var - > vsync_len - 1 ) ;
writel ( data , regs + VIDTCON0 ) ;
data = VIDTCON1_HBPD ( var - > left_margin - 1 ) |
VIDTCON1_HFPD ( var - > right_margin - 1 ) |
VIDTCON1_HSPW ( var - > hsync_len - 1 ) ;
writel ( data , regs + VIDTCON1 ) ;
data = VIDTCON2_LINEVAL ( var - > yres - 1 ) |
VIDTCON2_HOZVAL ( var - > xres - 1 ) ;
writel ( data , regs + VIDTCON2 ) ;
}
/* write the buffer address */
writel ( info - > fix . smem_start , regs + VIDW_BUF_START ( win_no ) ) ;
data = info - > fix . smem_start + info - > fix . line_length * var - > yres ;
writel ( data , regs + VIDW_BUF_END ( win_no ) ) ;
pagewidth = ( var - > xres * var - > bits_per_pixel ) > > 3 ;
data = VIDW_BUF_SIZE_OFFSET ( info - > fix . line_length - pagewidth ) |
VIDW_BUF_SIZE_PAGEWIDTH ( pagewidth ) ;
writel ( data , regs + VIDW_BUF_SIZE ( win_no ) ) ;
/* write 'OSD' registers to control position of framebuffer */
data = VIDOSDxA_TOPLEFT_X ( 0 ) | VIDOSDxA_TOPLEFT_Y ( 0 ) ;
writel ( data , regs + VIDOSD_A ( win_no ) ) ;
data = VIDOSDxB_BOTRIGHT_X ( s3c_fb_align_word ( var - > bits_per_pixel ,
var - > xres - 1 ) ) |
VIDOSDxB_BOTRIGHT_Y ( var - > yres - 1 ) ;
writel ( data , regs + VIDOSD_B ( win_no ) ) ;
data = var - > xres * var - > yres ;
Samsung SoC Framebuffer driver: add Alpha Channel support
Add support for the ARGB1888 and ARGB4888 hardware to the Samsung SoC
Framebuffer driver (s3c-fb.c).
ARGB1888 and ARGB4888 is decided by var->transp.length and this variable
is set by s3c_fb_check_var().
In s3c_fb_check_var(), if var->vits_per_pixel is 25 or 28, then
var->transp.length would be 1 or 3.
Therefore alpha mode(ARGB1888 or ARGB4888) could be decided through that
variable.
For using alpha mode, you need to set the following: This code should be
added to your machine code as platform data.
static struct s3c_fb_pd_win xxx_fb_win0 = {
/* this is to ensure we use win0 */
.win_mode = {
.pixclock = (8+8+8+240)*(38+4+38+400),
.left_margin = 8,
.right_margin = 8,
.upper_margin = 38,
.lower_margin = 38,
.hsync_len = 8,
.vsync_len = 4,
.xres = 240,
.yres = 400,
},
.max_bpp = 32,
.default_bpp = 24,
};
static struct s3c_fb_pd_win xxx_fb_win1 = {
.win_mode = {
.pixclock = (8+8+8+240)*(38+4+38+400),
.left_margin = 8,
.right_margin = 8,
.upper_margin = 38,
.lower_margin = 38,
.hsync_len = 8,
.vsync_len = 4,
.xres = 240,
.yres = 400,
},
.max_bpp = 32,
.default_bpp = 28,
};
static struct s3c_fb_platdata xxx_lcd_pdata __initdata = {
.win[0] = &ncp_fb_win0,
.win[1] = &ncp_fb_win1,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
.setup_gpio = xxx_fb_gpio_setup,
};
s3c_fb_set_platdata(&xxx_lcd_pdata);
The above code sets pixelformat for window0 layer to RGB888 and window1
layer to ARGB4888.
Signed-off-by: InKi Dae <inki.dae@samsung.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kyungmin Park <kmpark@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-06-17 02:34:27 +04:00
osdc_data = VIDISD14C_ALPHA1_R ( 0xf ) |
VIDISD14C_ALPHA1_G ( 0xf ) |
VIDISD14C_ALPHA1_B ( 0xf ) ;
2009-04-01 02:25:39 +04:00
if ( s3c_fb_has_osd_d ( win_no ) ) {
writel ( data , regs + VIDOSD_D ( win_no ) ) ;
Samsung SoC Framebuffer driver: add Alpha Channel support
Add support for the ARGB1888 and ARGB4888 hardware to the Samsung SoC
Framebuffer driver (s3c-fb.c).
ARGB1888 and ARGB4888 is decided by var->transp.length and this variable
is set by s3c_fb_check_var().
In s3c_fb_check_var(), if var->vits_per_pixel is 25 or 28, then
var->transp.length would be 1 or 3.
Therefore alpha mode(ARGB1888 or ARGB4888) could be decided through that
variable.
For using alpha mode, you need to set the following: This code should be
added to your machine code as platform data.
static struct s3c_fb_pd_win xxx_fb_win0 = {
/* this is to ensure we use win0 */
.win_mode = {
.pixclock = (8+8+8+240)*(38+4+38+400),
.left_margin = 8,
.right_margin = 8,
.upper_margin = 38,
.lower_margin = 38,
.hsync_len = 8,
.vsync_len = 4,
.xres = 240,
.yres = 400,
},
.max_bpp = 32,
.default_bpp = 24,
};
static struct s3c_fb_pd_win xxx_fb_win1 = {
.win_mode = {
.pixclock = (8+8+8+240)*(38+4+38+400),
.left_margin = 8,
.right_margin = 8,
.upper_margin = 38,
.lower_margin = 38,
.hsync_len = 8,
.vsync_len = 4,
.xres = 240,
.yres = 400,
},
.max_bpp = 32,
.default_bpp = 28,
};
static struct s3c_fb_platdata xxx_lcd_pdata __initdata = {
.win[0] = &ncp_fb_win0,
.win[1] = &ncp_fb_win1,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
.setup_gpio = xxx_fb_gpio_setup,
};
s3c_fb_set_platdata(&xxx_lcd_pdata);
The above code sets pixelformat for window0 layer to RGB888 and window1
layer to ARGB4888.
Signed-off-by: InKi Dae <inki.dae@samsung.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kyungmin Park <kmpark@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-06-17 02:34:27 +04:00
writel ( osdc_data , regs + VIDOSD_C ( win_no ) ) ;
2009-04-01 02:25:39 +04:00
} else
writel ( data , regs + VIDOSD_C ( win_no ) ) ;
data = WINCONx_ENWIN ;
/* note, since we have to round up the bits-per-pixel, we end up
* relying on the bitfield information for r / g / b / a to work out
* exactly which mode of operation is intended . */
switch ( var - > bits_per_pixel ) {
case 1 :
data | = WINCON0_BPPMODE_1BPP ;
data | = WINCONx_BITSWP ;
data | = WINCONx_BURSTLEN_4WORD ;
break ;
case 2 :
data | = WINCON0_BPPMODE_2BPP ;
data | = WINCONx_BITSWP ;
data | = WINCONx_BURSTLEN_8WORD ;
break ;
case 4 :
data | = WINCON0_BPPMODE_4BPP ;
data | = WINCONx_BITSWP ;
data | = WINCONx_BURSTLEN_8WORD ;
break ;
case 8 :
if ( var - > transp . length ! = 0 )
data | = WINCON1_BPPMODE_8BPP_1232 ;
else
data | = WINCON0_BPPMODE_8BPP_PALETTE ;
data | = WINCONx_BURSTLEN_8WORD ;
data | = WINCONx_BYTSWP ;
break ;
case 16 :
if ( var - > transp . length ! = 0 )
data | = WINCON1_BPPMODE_16BPP_A1555 ;
else
data | = WINCON0_BPPMODE_16BPP_565 ;
data | = WINCONx_HAWSWP ;
data | = WINCONx_BURSTLEN_16WORD ;
break ;
case 24 :
case 32 :
if ( var - > red . length = = 6 ) {
if ( var - > transp . length ! = 0 )
data | = WINCON1_BPPMODE_19BPP_A1666 ;
else
data | = WINCON1_BPPMODE_18BPP_666 ;
Samsung SoC Framebuffer driver: add Alpha Channel support
Add support for the ARGB1888 and ARGB4888 hardware to the Samsung SoC
Framebuffer driver (s3c-fb.c).
ARGB1888 and ARGB4888 is decided by var->transp.length and this variable
is set by s3c_fb_check_var().
In s3c_fb_check_var(), if var->vits_per_pixel is 25 or 28, then
var->transp.length would be 1 or 3.
Therefore alpha mode(ARGB1888 or ARGB4888) could be decided through that
variable.
For using alpha mode, you need to set the following: This code should be
added to your machine code as platform data.
static struct s3c_fb_pd_win xxx_fb_win0 = {
/* this is to ensure we use win0 */
.win_mode = {
.pixclock = (8+8+8+240)*(38+4+38+400),
.left_margin = 8,
.right_margin = 8,
.upper_margin = 38,
.lower_margin = 38,
.hsync_len = 8,
.vsync_len = 4,
.xres = 240,
.yres = 400,
},
.max_bpp = 32,
.default_bpp = 24,
};
static struct s3c_fb_pd_win xxx_fb_win1 = {
.win_mode = {
.pixclock = (8+8+8+240)*(38+4+38+400),
.left_margin = 8,
.right_margin = 8,
.upper_margin = 38,
.lower_margin = 38,
.hsync_len = 8,
.vsync_len = 4,
.xres = 240,
.yres = 400,
},
.max_bpp = 32,
.default_bpp = 28,
};
static struct s3c_fb_platdata xxx_lcd_pdata __initdata = {
.win[0] = &ncp_fb_win0,
.win[1] = &ncp_fb_win1,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
.setup_gpio = xxx_fb_gpio_setup,
};
s3c_fb_set_platdata(&xxx_lcd_pdata);
The above code sets pixelformat for window0 layer to RGB888 and window1
layer to ARGB4888.
Signed-off-by: InKi Dae <inki.dae@samsung.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kyungmin Park <kmpark@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-06-17 02:34:27 +04:00
} else if ( var - > transp . length = = 1 )
data | = WINCON1_BPPMODE_25BPP_A1888
| WINCON1_BLD_PIX ;
else if ( var - > transp . length = = 4 )
data | = WINCON1_BPPMODE_28BPP_A4888
| WINCON1_BLD_PIX | WINCON1_ALPHA_SEL ;
2009-04-01 02:25:39 +04:00
else
data | = WINCON0_BPPMODE_24BPP_888 ;
data | = WINCONx_BURSTLEN_16WORD ;
break ;
}
Samsung SoC Framebuffer driver: add Alpha Channel support
Add support for the ARGB1888 and ARGB4888 hardware to the Samsung SoC
Framebuffer driver (s3c-fb.c).
ARGB1888 and ARGB4888 is decided by var->transp.length and this variable
is set by s3c_fb_check_var().
In s3c_fb_check_var(), if var->vits_per_pixel is 25 or 28, then
var->transp.length would be 1 or 3.
Therefore alpha mode(ARGB1888 or ARGB4888) could be decided through that
variable.
For using alpha mode, you need to set the following: This code should be
added to your machine code as platform data.
static struct s3c_fb_pd_win xxx_fb_win0 = {
/* this is to ensure we use win0 */
.win_mode = {
.pixclock = (8+8+8+240)*(38+4+38+400),
.left_margin = 8,
.right_margin = 8,
.upper_margin = 38,
.lower_margin = 38,
.hsync_len = 8,
.vsync_len = 4,
.xres = 240,
.yres = 400,
},
.max_bpp = 32,
.default_bpp = 24,
};
static struct s3c_fb_pd_win xxx_fb_win1 = {
.win_mode = {
.pixclock = (8+8+8+240)*(38+4+38+400),
.left_margin = 8,
.right_margin = 8,
.upper_margin = 38,
.lower_margin = 38,
.hsync_len = 8,
.vsync_len = 4,
.xres = 240,
.yres = 400,
},
.max_bpp = 32,
.default_bpp = 28,
};
static struct s3c_fb_platdata xxx_lcd_pdata __initdata = {
.win[0] = &ncp_fb_win0,
.win[1] = &ncp_fb_win1,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
.setup_gpio = xxx_fb_gpio_setup,
};
s3c_fb_set_platdata(&xxx_lcd_pdata);
The above code sets pixelformat for window0 layer to RGB888 and window1
layer to ARGB4888.
Signed-off-by: InKi Dae <inki.dae@samsung.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kyungmin Park <kmpark@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-06-17 02:34:27 +04:00
/* It has no color key control register for window0 */
if ( win_no > 0 ) {
u32 keycon0_data = 0 , keycon1_data = 0 ;
keycon0_data = ~ ( WxKEYCON0_KEYBL_EN |
WxKEYCON0_KEYEN_F |
WxKEYCON0_DIRCON ) | WxKEYCON0_COMPKEY ( 0 ) ;
keycon1_data = WxKEYCON1_COLVAL ( 0xffffff ) ;
writel ( keycon0_data , regs + WxKEYCONy ( win_no - 1 , 0 ) ) ;
writel ( keycon1_data , regs + WxKEYCONy ( win_no - 1 , 1 ) ) ;
}
2009-04-01 02:25:39 +04:00
writel ( data , regs + WINCON ( win_no ) ) ;
writel ( 0x0 , regs + WINxMAP ( win_no ) ) ;
return 0 ;
}
/**
* s3c_fb_update_palette ( ) - set or schedule a palette update .
* @ sfb : The hardware information .
* @ win : The window being updated .
* @ reg : The palette index being changed .
* @ value : The computed palette value .
*
* Change the value of a palette register , either by directly writing to
* the palette ( this requires the palette RAM to be disconnected from the
* hardware whilst this is in progress ) or schedule the update for later .
*
* At the moment , since we have no VSYNC interrupt support , we simply set
* the palette entry directly .
*/
static void s3c_fb_update_palette ( struct s3c_fb * sfb ,
struct s3c_fb_win * win ,
unsigned int reg ,
u32 value )
{
void __iomem * palreg ;
u32 palcon ;
palreg = sfb - > regs + s3c_fb_pal_reg ( win - > index , reg ) ;
dev_dbg ( sfb - > dev , " %s: win %d, reg %d (%p): %08x \n " ,
__func__ , win - > index , reg , palreg , value ) ;
win - > palette_buffer [ reg ] = value ;
palcon = readl ( sfb - > regs + WPALCON ) ;
writel ( palcon | WPALCON_PAL_UPDATE , sfb - > regs + WPALCON ) ;
if ( s3c_fb_pal_is16 ( win - > index ) )
writew ( value , palreg ) ;
else
writel ( value , palreg ) ;
writel ( palcon , sfb - > regs + WPALCON ) ;
}
static inline unsigned int chan_to_field ( unsigned int chan ,
struct fb_bitfield * bf )
{
chan & = 0xffff ;
chan > > = 16 - bf - > length ;
return chan < < bf - > offset ;
}
/**
* s3c_fb_setcolreg ( ) - framebuffer layer request to change palette .
* @ regno : The palette index to change .
* @ red : The red field for the palette data .
* @ green : The green field for the palette data .
* @ blue : The blue field for the palette data .
* @ trans : The transparency ( alpha ) field for the palette data .
* @ info : The framebuffer being changed .
*/
static int s3c_fb_setcolreg ( unsigned regno ,
unsigned red , unsigned green , unsigned blue ,
unsigned transp , struct fb_info * info )
{
struct s3c_fb_win * win = info - > par ;
struct s3c_fb * sfb = win - > parent ;
unsigned int val ;
dev_dbg ( sfb - > dev , " %s: win %d: %d => rgb=%d/%d/%d \n " ,
__func__ , win - > index , regno , red , green , blue ) ;
switch ( info - > fix . visual ) {
case FB_VISUAL_TRUECOLOR :
/* true-colour, use pseudo-palette */
if ( regno < 16 ) {
u32 * pal = info - > pseudo_palette ;
val = chan_to_field ( red , & info - > var . red ) ;
val | = chan_to_field ( green , & info - > var . green ) ;
val | = chan_to_field ( blue , & info - > var . blue ) ;
pal [ regno ] = val ;
}
break ;
case FB_VISUAL_PSEUDOCOLOR :
if ( regno < s3c_fb_win_pal_size ( win - > index ) ) {
val = chan_to_field ( red , & win - > palette . r ) ;
val | = chan_to_field ( green , & win - > palette . g ) ;
val | = chan_to_field ( blue , & win - > palette . b ) ;
s3c_fb_update_palette ( sfb , win , regno , val ) ;
}
break ;
default :
return 1 ; /* unknown type */
}
return 0 ;
}
/**
* s3c_fb_enable ( ) - Set the state of the main LCD output
* @ sfb : The main framebuffer state .
* @ enable : The state to set .
*/
static void s3c_fb_enable ( struct s3c_fb * sfb , int enable )
{
u32 vidcon0 = readl ( sfb - > regs + VIDCON0 ) ;
if ( enable )
vidcon0 | = VIDCON0_ENVID | VIDCON0_ENVID_F ;
else {
/* see the note in the framebuffer datasheet about
* why you cannot take both of these bits down at the
* same time . */
if ( ! ( vidcon0 & VIDCON0_ENVID ) )
return ;
vidcon0 | = VIDCON0_ENVID ;
vidcon0 & = ~ VIDCON0_ENVID_F ;
}
writel ( vidcon0 , sfb - > regs + VIDCON0 ) ;
}
/**
* s3c_fb_blank ( ) - blank or unblank the given window
* @ blank_mode : The blank state from FB_BLANK_ *
* @ info : The framebuffer to blank .
*
* Framebuffer layer request to change the power state .
*/
static int s3c_fb_blank ( int blank_mode , struct fb_info * info )
{
struct s3c_fb_win * win = info - > par ;
struct s3c_fb * sfb = win - > parent ;
unsigned int index = win - > index ;
u32 wincon ;
dev_dbg ( sfb - > dev , " blank mode %d \n " , blank_mode ) ;
wincon = readl ( sfb - > regs + WINCON ( index ) ) ;
switch ( blank_mode ) {
case FB_BLANK_POWERDOWN :
wincon & = ~ WINCONx_ENWIN ;
sfb - > enabled & = ~ ( 1 < < index ) ;
/* fall through to FB_BLANK_NORMAL */
case FB_BLANK_NORMAL :
/* disable the DMA and display 0x0 (black) */
writel ( WINxMAP_MAP | WINxMAP_MAP_COLOUR ( 0x0 ) ,
sfb - > regs + WINxMAP ( index ) ) ;
break ;
case FB_BLANK_UNBLANK :
writel ( 0x0 , sfb - > regs + WINxMAP ( index ) ) ;
wincon | = WINCONx_ENWIN ;
sfb - > enabled | = ( 1 < < index ) ;
break ;
case FB_BLANK_VSYNC_SUSPEND :
case FB_BLANK_HSYNC_SUSPEND :
default :
return 1 ;
}
writel ( wincon , sfb - > regs + WINCON ( index ) ) ;
/* Check the enabled state to see if we need to be running the
* main LCD interface , as if there are no active windows then
* it is highly likely that we also do not need to output
* anything .
*/
/* We could do something like the following code, but the current
* system of using framebuffer events means that we cannot make
* the distinction between just window 0 being inactive and all
* the windows being down .
*
* s3c_fb_enable ( sfb , sfb - > enabled ? 1 : 0 ) ;
*/
/* we're stuck with this until we can do something about overriding
* the power control using the blanking event for a single fb .
*/
if ( index = = 0 )
s3c_fb_enable ( sfb , blank_mode ! = FB_BLANK_POWERDOWN ? 1 : 0 ) ;
return 0 ;
}
static struct fb_ops s3c_fb_ops = {
. owner = THIS_MODULE ,
. fb_check_var = s3c_fb_check_var ,
. fb_set_par = s3c_fb_set_par ,
. fb_blank = s3c_fb_blank ,
. fb_setcolreg = s3c_fb_setcolreg ,
. fb_fillrect = cfb_fillrect ,
. fb_copyarea = cfb_copyarea ,
. fb_imageblit = cfb_imageblit ,
} ;
/**
* s3c_fb_alloc_memory ( ) - allocate display memory for framebuffer window
* @ sfb : The base resources for the hardware .
* @ win : The window to initialise memory for .
*
* Allocate memory for the given framebuffer .
*/
static int __devinit s3c_fb_alloc_memory ( struct s3c_fb * sfb ,
struct s3c_fb_win * win )
{
struct s3c_fb_pd_win * windata = win - > windata ;
unsigned int real_size , virt_size , size ;
struct fb_info * fbi = win - > fbinfo ;
dma_addr_t map_dma ;
dev_dbg ( sfb - > dev , " allocating memory for display \n " ) ;
real_size = windata - > win_mode . xres * windata - > win_mode . yres ;
virt_size = windata - > virtual_x * windata - > virtual_y ;
dev_dbg ( sfb - > dev , " real_size=%u (%u.%u), virt_size=%u (%u.%u) \n " ,
real_size , windata - > win_mode . xres , windata - > win_mode . yres ,
virt_size , windata - > virtual_x , windata - > virtual_y ) ;
size = ( real_size > virt_size ) ? real_size : virt_size ;
size * = ( windata - > max_bpp > 16 ) ? 32 : windata - > max_bpp ;
size / = 8 ;
fbi - > fix . smem_len = size ;
size = PAGE_ALIGN ( size ) ;
dev_dbg ( sfb - > dev , " want %u bytes for window \n " , size ) ;
fbi - > screen_base = dma_alloc_writecombine ( sfb - > dev , size ,
& map_dma , GFP_KERNEL ) ;
if ( ! fbi - > screen_base )
return - ENOMEM ;
dev_dbg ( sfb - > dev , " mapped %x to %p \n " ,
( unsigned int ) map_dma , fbi - > screen_base ) ;
memset ( fbi - > screen_base , 0x0 , size ) ;
fbi - > fix . smem_start = map_dma ;
return 0 ;
}
/**
* s3c_fb_free_memory ( ) - free the display memory for the given window
* @ sfb : The base resources for the hardware .
* @ win : The window to free the display memory for .
*
* Free the display memory allocated by s3c_fb_alloc_memory ( ) .
*/
static void s3c_fb_free_memory ( struct s3c_fb * sfb , struct s3c_fb_win * win )
{
struct fb_info * fbi = win - > fbinfo ;
dma_free_writecombine ( sfb - > dev , PAGE_ALIGN ( fbi - > fix . smem_len ) ,
fbi - > screen_base , fbi - > fix . smem_start ) ;
}
/**
* s3c_fb_release_win ( ) - release resources for a framebuffer window .
* @ win : The window to cleanup the resources for .
*
* Release the resources that where claimed for the hardware window ,
* such as the framebuffer instance and any memory claimed for it .
*/
static void s3c_fb_release_win ( struct s3c_fb * sfb , struct s3c_fb_win * win )
{
2009-06-17 02:34:33 +04:00
if ( win - > fbinfo ) {
unregister_framebuffer ( win - > fbinfo ) ;
fb_dealloc_cmap ( & win - > fbinfo - > cmap ) ;
s3c_fb_free_memory ( sfb , win ) ;
framebuffer_release ( win - > fbinfo ) ;
}
2009-04-01 02:25:39 +04:00
}
/**
* s3c_fb_probe_win ( ) - register an hardware window
* @ sfb : The base resources for the hardware
* @ res : Pointer to where to place the resultant window .
*
* Allocate and do the basic initialisation for one of the hardware ' s graphics
* windows .
*/
static int __devinit s3c_fb_probe_win ( struct s3c_fb * sfb , unsigned int win_no ,
struct s3c_fb_win * * res )
{
struct fb_var_screeninfo * var ;
struct fb_videomode * initmode ;
struct s3c_fb_pd_win * windata ;
struct s3c_fb_win * win ;
struct fb_info * fbinfo ;
int palette_size ;
int ret ;
dev_dbg ( sfb - > dev , " probing window %d \n " , win_no ) ;
palette_size = s3c_fb_win_pal_size ( win_no ) ;
fbinfo = framebuffer_alloc ( sizeof ( struct s3c_fb_win ) +
palette_size * sizeof ( u32 ) , sfb - > dev ) ;
if ( ! fbinfo ) {
dev_err ( sfb - > dev , " failed to allocate framebuffer \n " ) ;
return - ENOENT ;
}
windata = sfb - > pdata - > win [ win_no ] ;
initmode = & windata - > win_mode ;
WARN_ON ( windata - > max_bpp = = 0 ) ;
WARN_ON ( windata - > win_mode . xres = = 0 ) ;
WARN_ON ( windata - > win_mode . yres = = 0 ) ;
win = fbinfo - > par ;
var = & fbinfo - > var ;
win - > fbinfo = fbinfo ;
win - > parent = sfb ;
win - > windata = windata ;
win - > index = win_no ;
win - > palette_buffer = ( u32 * ) ( win + 1 ) ;
ret = s3c_fb_alloc_memory ( sfb , win ) ;
if ( ret ) {
dev_err ( sfb - > dev , " failed to allocate display memory \n " ) ;
2009-06-17 02:34:33 +04:00
return ret ;
2009-04-01 02:25:39 +04:00
}
/* setup the r/b/g positions for the window's palette */
s3c_fb_init_palette ( win_no , & win - > palette ) ;
/* setup the initial video mode from the window */
fb_videomode_to_var ( & fbinfo - > var , initmode ) ;
fbinfo - > fix . type = FB_TYPE_PACKED_PIXELS ;
fbinfo - > fix . accel = FB_ACCEL_NONE ;
fbinfo - > var . activate = FB_ACTIVATE_NOW ;
fbinfo - > var . vmode = FB_VMODE_NONINTERLACED ;
fbinfo - > var . bits_per_pixel = windata - > default_bpp ;
fbinfo - > fbops = & s3c_fb_ops ;
fbinfo - > flags = FBINFO_FLAG_DEFAULT ;
fbinfo - > pseudo_palette = & win - > pseudo_palette ;
/* prepare to actually start the framebuffer */
ret = s3c_fb_check_var ( & fbinfo - > var , fbinfo ) ;
if ( ret < 0 ) {
dev_err ( sfb - > dev , " check_var failed on initial video params \n " ) ;
2009-06-17 02:34:33 +04:00
return ret ;
2009-04-01 02:25:39 +04:00
}
/* create initial colour map */
ret = fb_alloc_cmap ( & fbinfo - > cmap , s3c_fb_win_pal_size ( win_no ) , 1 ) ;
if ( ret = = 0 )
fb_set_cmap ( & fbinfo - > cmap , fbinfo ) ;
else
dev_err ( sfb - > dev , " failed to allocate fb cmap \n " ) ;
s3c_fb_set_par ( fbinfo ) ;
dev_dbg ( sfb - > dev , " about to register framebuffer \n " ) ;
/* run the check_var and set_par on our configuration. */
ret = register_framebuffer ( fbinfo ) ;
if ( ret < 0 ) {
dev_err ( sfb - > dev , " failed to register framebuffer \n " ) ;
2009-06-17 02:34:33 +04:00
return ret ;
2009-04-01 02:25:39 +04:00
}
* res = win ;
dev_info ( sfb - > dev , " window %d: fb %s \n " , win_no , fbinfo - > fix . id ) ;
return 0 ;
}
/**
* s3c_fb_clear_win ( ) - clear hardware window registers .
* @ sfb : The base resources for the hardware .
* @ win : The window to process .
*
* Reset the specific window registers to a known state .
*/
static void s3c_fb_clear_win ( struct s3c_fb * sfb , int win )
{
void __iomem * regs = sfb - > regs ;
writel ( 0 , regs + WINCON ( win ) ) ;
writel ( 0xffffff , regs + WxKEYCONy ( win , 0 ) ) ;
writel ( 0xffffff , regs + WxKEYCONy ( win , 1 ) ) ;
writel ( 0 , regs + VIDOSD_A ( win ) ) ;
writel ( 0 , regs + VIDOSD_B ( win ) ) ;
writel ( 0 , regs + VIDOSD_C ( win ) ) ;
}
static int __devinit s3c_fb_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct s3c_fb_platdata * pd ;
struct s3c_fb * sfb ;
struct resource * res ;
int win ;
int ret = 0 ;
pd = pdev - > dev . platform_data ;
if ( ! pd ) {
dev_err ( dev , " no platform data specified \n " ) ;
return - EINVAL ;
}
sfb = kzalloc ( sizeof ( struct s3c_fb ) , GFP_KERNEL ) ;
if ( ! sfb ) {
dev_err ( dev , " no memory for framebuffers \n " ) ;
return - ENOMEM ;
}
sfb - > dev = dev ;
sfb - > pdata = pd ;
sfb - > bus_clk = clk_get ( dev , " lcd " ) ;
if ( IS_ERR ( sfb - > bus_clk ) ) {
dev_err ( dev , " failed to get bus clock \n " ) ;
goto err_sfb ;
}
clk_enable ( sfb - > bus_clk ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res ) {
dev_err ( dev , " failed to find registers \n " ) ;
ret = - ENOENT ;
goto err_clk ;
}
sfb - > regs_res = request_mem_region ( res - > start , resource_size ( res ) ,
dev_name ( dev ) ) ;
if ( ! sfb - > regs_res ) {
dev_err ( dev , " failed to claim register region \n " ) ;
ret = - ENOENT ;
goto err_clk ;
}
sfb - > regs = ioremap ( res - > start , resource_size ( res ) ) ;
if ( ! sfb - > regs ) {
dev_err ( dev , " failed to map registers \n " ) ;
ret = - ENXIO ;
goto err_req_region ;
}
dev_dbg ( dev , " got resources (regs %p), probing windows \n " , sfb - > regs ) ;
/* setup gpio and output polarity controls */
pd - > setup_gpio ( ) ;
writel ( pd - > vidcon1 , sfb - > regs + VIDCON1 ) ;
/* zero all windows before we do anything */
for ( win = 0 ; win < S3C_FB_MAX_WIN ; win + + )
s3c_fb_clear_win ( sfb , win ) ;
/* we have the register setup, start allocating framebuffers */
for ( win = 0 ; win < S3C_FB_MAX_WIN ; win + + ) {
if ( ! pd - > win [ win ] )
continue ;
ret = s3c_fb_probe_win ( sfb , win , & sfb - > windows [ win ] ) ;
if ( ret < 0 ) {
dev_err ( dev , " failed to create window %d \n " , win ) ;
for ( ; win > = 0 ; win - - )
s3c_fb_release_win ( sfb , sfb - > windows [ win ] ) ;
goto err_ioremap ;
}
}
platform_set_drvdata ( pdev , sfb ) ;
return 0 ;
err_ioremap :
iounmap ( sfb - > regs ) ;
err_req_region :
release_resource ( sfb - > regs_res ) ;
kfree ( sfb - > regs_res ) ;
err_clk :
clk_disable ( sfb - > bus_clk ) ;
clk_put ( sfb - > bus_clk ) ;
err_sfb :
kfree ( sfb ) ;
return ret ;
}
/**
* s3c_fb_remove ( ) - Cleanup on module finalisation
* @ pdev : The platform device we are bound to .
*
* Shutdown and then release all the resources that the driver allocated
* on initialisation .
*/
static int __devexit s3c_fb_remove ( struct platform_device * pdev )
{
struct s3c_fb * sfb = platform_get_drvdata ( pdev ) ;
int win ;
2009-07-30 02:02:10 +04:00
for ( win = 0 ; win < S3C_FB_MAX_WIN ; win + + )
2009-05-29 01:34:35 +04:00
if ( sfb - > windows [ win ] )
s3c_fb_release_win ( sfb , sfb - > windows [ win ] ) ;
2009-04-01 02:25:39 +04:00
iounmap ( sfb - > regs ) ;
clk_disable ( sfb - > bus_clk ) ;
clk_put ( sfb - > bus_clk ) ;
release_resource ( sfb - > regs_res ) ;
kfree ( sfb - > regs_res ) ;
kfree ( sfb ) ;
return 0 ;
}
# ifdef CONFIG_PM
static int s3c_fb_suspend ( struct platform_device * pdev , pm_message_t state )
{
struct s3c_fb * sfb = platform_get_drvdata ( pdev ) ;
struct s3c_fb_win * win ;
int win_no ;
2009-07-30 02:02:10 +04:00
for ( win_no = S3C_FB_MAX_WIN - 1 ; win_no > = 0 ; win_no - - ) {
2009-04-01 02:25:39 +04:00
win = sfb - > windows [ win_no ] ;
if ( ! win )
continue ;
/* use the blank function to push into power-down */
s3c_fb_blank ( FB_BLANK_POWERDOWN , win - > fbinfo ) ;
}
clk_disable ( sfb - > bus_clk ) ;
return 0 ;
}
static int s3c_fb_resume ( struct platform_device * pdev )
{
struct s3c_fb * sfb = platform_get_drvdata ( pdev ) ;
2009-05-29 01:34:35 +04:00
struct s3c_fb_platdata * pd = sfb - > pdata ;
2009-04-01 02:25:39 +04:00
struct s3c_fb_win * win ;
int win_no ;
clk_enable ( sfb - > bus_clk ) ;
2009-05-29 01:34:35 +04:00
/* setup registers */
writel ( pd - > vidcon1 , sfb - > regs + VIDCON1 ) ;
/* zero all windows before we do anything */
for ( win_no = 0 ; win_no < S3C_FB_MAX_WIN ; win_no + + )
s3c_fb_clear_win ( sfb , win_no ) ;
/* restore framebuffers */
2009-04-01 02:25:39 +04:00
for ( win_no = 0 ; win_no < S3C_FB_MAX_WIN ; win_no + + ) {
win = sfb - > windows [ win_no ] ;
if ( ! win )
continue ;
dev_dbg ( & pdev - > dev , " resuming window %d \n " , win_no ) ;
s3c_fb_set_par ( win - > fbinfo ) ;
}
return 0 ;
}
# else
# define s3c_fb_suspend NULL
# define s3c_fb_resume NULL
# endif
static struct platform_driver s3c_fb_driver = {
. probe = s3c_fb_probe ,
2009-09-23 03:47:55 +04:00
. remove = __devexit_p ( s3c_fb_remove ) ,
2009-04-01 02:25:39 +04:00
. suspend = s3c_fb_suspend ,
. resume = s3c_fb_resume ,
. driver = {
. name = " s3c-fb " ,
. owner = THIS_MODULE ,
} ,
} ;
static int __init s3c_fb_init ( void )
{
return platform_driver_register ( & s3c_fb_driver ) ;
}
static void __exit s3c_fb_cleanup ( void )
{
platform_driver_unregister ( & s3c_fb_driver ) ;
}
module_init ( s3c_fb_init ) ;
module_exit ( s3c_fb_cleanup ) ;
MODULE_AUTHOR ( " Ben Dooks <ben@simtec.co.uk> " ) ;
MODULE_DESCRIPTION ( " Samsung S3C SoC Framebuffer driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:s3c-fb " ) ;